about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock23
-rw-r--r--bootstrap.example.toml3
-rw-r--r--compiler/rustc_ast/src/token.rs20
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs42
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs4
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/crate_level.rs148
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/prelude.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs22
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs10
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs11
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh4
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/test.rs22
-rw-r--r--compiler/rustc_codegen_gcc/src/back/lto.rs13
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs51
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs41
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs7
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl14
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/back/lto.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs52
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs137
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs80
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs27
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs6
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs5
-rw-r--r--compiler/rustc_driver_impl/messages.ftl4
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs5
-rw-r--r--compiler/rustc_errors/src/emitter.rs1
-rw-r--r--compiler/rustc_errors/src/lib.rs29
-rw-r--r--compiler/rustc_expand/src/base.rs3
-rw-r--r--compiler/rustc_expand/src/errors.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs20
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/attrs/data_structures.rs13
-rw-r--r--compiler/rustc_hir/src/attrs/encode_cross_crate.rs4
-rw-r--r--compiler/rustc_hir/src/attrs/pretty_printing.rs4
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_hir/src/limit.rs63
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs146
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs8
-rw-r--r--compiler/rustc_index/src/interval.rs54
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs34
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs56
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs77
-rw-r--r--compiler/rustc_infer/src/infer/context.rs10
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs9
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs47
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/undo_log.rs4
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs116
-rw-r--r--compiler/rustc_interface/messages.ftl4
-rw-r--r--compiler/rustc_interface/src/errors.rs10
-rw-r--r--compiler/rustc_interface/src/interface.rs6
-rw-r--r--compiler/rustc_interface/src/limits.rs88
-rw-r--r--compiler/rustc_interface/src/passes.rs54
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs27
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/types.rs875
-rw-r--r--compiler/rustc_lint/src/types/improper_ctypes.rs1016
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs54
-rw-r--r--compiler/rustc_llvm/build.rs8
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp11
-rw-r--r--compiler/rustc_log/Cargo.toml5
-rw-r--r--compiler/rustc_log/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/creader.rs18
-rw-r--r--compiler/rustc_middle/src/error.rs2
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs1
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/middle/region.rs39
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs2
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs22
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs18
-rw-r--r--compiler/rustc_middle/src/query/mod.rs11
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs10
-rw-r--r--compiler/rustc_middle/src/ty/context.rs35
-rw-r--r--compiler/rustc_middle/src/ty/error.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs32
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs12
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs37
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs39
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs37
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs68
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs9
-rw-r--r--compiler/rustc_mir_transform/src/check_inline_always_target_features.rs88
-rw-r--r--compiler/rustc_mir_transform/src/coverage/expansion.rs2
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs11
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs794
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs41
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs67
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs5
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs18
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs4
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/move_check.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs50
-rw-r--r--compiler/rustc_next_trait_solver/src/coherence.rs16
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs10
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs70
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs10
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs19
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs21
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs6
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs35
-rw-r--r--compiler/rustc_parse/src/lib.rs37
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_passes/messages.ftl1
-rw-r--r--compiler/rustc_passes/src/check_attr.rs4
-rw-r--r--compiler/rustc_passes/src/errors.rs18
-rw-r--r--compiler/rustc_passes/src/liveness.rs50
-rw-r--r--compiler/rustc_query_impl/Cargo.toml1
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs2
-rw-r--r--compiler/rustc_query_system/messages.ftl4
-rw-r--r--compiler/rustc_query_system/src/error.rs2
-rw-r--r--compiler/rustc_resolve/messages.ftl2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs188
-rw-r--r--compiler/rustc_resolve/src/errors.rs12
-rw-r--r--compiler/rustc_resolve/src/late.rs52
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs16
-rw-r--r--compiler/rustc_session/src/options.rs71
-rw-r--r--compiler/rustc_session/src/session.rs62
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs8
-rw-r--r--compiler/rustc_target/src/callconv/loongarch.rs137
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs81
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs77
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs5
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs18
-rw-r--r--compiler/rustc_traits/src/evaluate_obligation.rs2
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs2
-rw-r--r--compiler/rustc_type_ir/Cargo.toml1
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs109
-rw-r--r--compiler/rustc_type_ir/src/fast_reject.rs14
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs2
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs30
-rw-r--r--compiler/rustc_type_ir/src/interner.rs77
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs5
-rw-r--r--compiler/rustc_type_ir/src/relate.rs4
-rw-r--r--compiler/rustc_type_ir/src/solve/inspect.rs2
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs12
-rw-r--r--compiler/rustc_type_ir/src/ty_kind/closure.rs4
-rw-r--r--library/Cargo.lock6
-rw-r--r--library/alloc/src/raw_vec/mod.rs27
-rw-r--r--library/alloc/src/str.rs5
-rw-r--r--library/core/src/array/mod.rs1
-rw-r--r--library/core/src/borrow.rs6
-rw-r--r--library/core/src/char/methods.rs38
-rw-r--r--library/core/src/clone.rs3
-rw-r--r--library/core/src/cmp.rs3
-rw-r--r--library/core/src/cmp/bytewise.rs2
-rw-r--r--library/core/src/convert/mod.rs18
-rw-r--r--library/core/src/default.rs5
-rw-r--r--library/core/src/fmt/num.rs389
-rw-r--r--library/core/src/intrinsics/fallback.rs78
-rw-r--r--library/core/src/intrinsics/mod.rs55
-rw-r--r--library/core/src/iter/adapters/chain.rs1
-rw-r--r--library/core/src/iter/adapters/peekable.rs102
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/marker.rs3
-rw-r--r--library/core/src/num/f128.rs8
-rw-r--r--library/core/src/num/f16.rs8
-rw-r--r--library/core/src/num/f32.rs14
-rw-r--r--library/core/src/num/f64.rs8
-rw-r--r--library/core/src/num/int_macros.rs119
-rw-r--r--library/core/src/num/mod.rs24
-rw-r--r--library/core/src/num/uint_macros.rs189
-rw-r--r--library/core/src/ops/arith.rs33
-rw-r--r--library/core/src/ops/bit.rs33
-rw-r--r--library/core/src/ops/deref.rs6
-rw-r--r--library/core/src/ops/drop.rs3
-rw-r--r--library/core/src/ops/function.rs9
-rw-r--r--library/core/src/ops/index.rs6
-rw-r--r--library/core/src/ops/range.rs1
-rw-r--r--library/core/src/ops/try_trait.rs9
-rw-r--r--library/core/src/option.rs4
-rw-r--r--library/core/src/pat.rs3
-rw-r--r--library/core/src/ptr/mut_ptr.rs1
-rw-r--r--library/core/src/slice/cmp.rs3
-rw-r--r--library/core/src/slice/index.rs2
-rw-r--r--library/core/src/str/traits.rs3
-rw-r--r--library/core/src/unicode/unicode_data.rs521
-rw-r--r--library/coretests/benches/fmt.rs24
-rw-r--r--library/coretests/tests/floats/f128.rs23
-rw-r--r--library/coretests/tests/floats/f16.rs21
-rw-r--r--library/coretests/tests/floats/f32.rs23
-rw-r--r--library/coretests/tests/floats/f64.rs21
-rw-r--r--library/coretests/tests/floats/mod.rs39
-rw-r--r--library/coretests/tests/iter/adapters/peekable.rs86
-rw-r--r--library/coretests/tests/lib.rs2
-rw-r--r--library/coretests/tests/num/uint_macros.rs36
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/num/int.rs1
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/num/uint.rs1
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/fs/tests.rs116
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/num/f128.rs10
-rw-r--r--library/std/src/num/f16.rs10
-rw-r--r--library/std/src/num/f32.rs44
-rw-r--r--library/std/src/num/f64.rs16
-rw-r--r--library/std/src/os/cygwin/mod.rs1
-rw-r--r--library/std/src/os/cygwin/net.rs17
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/net/linux_ext/mod.rs4
-rw-r--r--library/std/src/os/net/mod.rs2
-rw-r--r--library/std/src/os/unix/fs.rs89
-rw-r--r--library/std/src/os/unix/net/addr.rs8
-rw-r--r--library/std/src/os/unix/net/ancillary.rs31
-rw-r--r--library/std/src/os/unix/net/datagram.rs52
-rw-r--r--library/std/src/os/unix/net/mod.rs6
-rw-r--r--library/std/src/os/unix/net/stream.rs26
-rw-r--r--library/std/src/os/unix/net/tests.rs27
-rw-r--r--library/std/src/os/windows/fs.rs43
-rw-r--r--library/std/src/path.rs18
-rw-r--r--library/std/src/sys/fd/unix.rs65
-rw-r--r--library/std/src/sys/fs/unix.rs70
-rw-r--r--library/std/src/sys/fs/windows.rs4
-rw-r--r--library/std/src/sys/mod.rs1
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs12
-rw-r--r--library/std/src/sys/pal/windows/handle.rs13
-rw-r--r--library/std/src/sys/platform_version/darwin/core_foundation.rs180
-rw-r--r--library/std/src/sys/platform_version/darwin/mod.rs351
-rw-r--r--library/std/src/sys/platform_version/darwin/public_extern.rs151
-rw-r--r--library/std/src/sys/platform_version/darwin/tests.rs379
-rw-r--r--library/std/src/sys/platform_version/mod.rs13
-rw-r--r--library/std/src/sys/stdio/mod.rs10
-rw-r--r--library/std/src/sys/stdio/wasip1.rs (renamed from library/std/src/sys/stdio/wasi.rs)0
-rw-r--r--library/std/src/sys/stdio/wasip2.rs120
-rw-r--r--library/std/tests/floats/f32.rs14
-rw-r--r--library/std/tests/path.rs8
-rw-r--r--package-lock.json473
-rw-r--r--package.json2
-rw-r--r--src/bootstrap/Cargo.lock138
-rw-r--r--src/bootstrap/Cargo.toml4
-rw-r--r--src/bootstrap/mk/Makefile.in2
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs25
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs21
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs21
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs115
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs214
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs22
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs30
-rw-r--r--src/bootstrap/src/core/builder/mod.rs4
-rw-r--r--src/bootstrap/src/core/builder/tests.rs171
-rw-r--r--src/bootstrap/src/core/config/config.rs3
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs2
-rw-r--r--src/bootstrap/src/lib.rs23
-rw-r--r--src/bootstrap/src/utils/cc_detect/tests.rs21
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/dist-various-1/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/pr-check-2/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile10
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile2
-rw-r--r--src/doc/favicon.inc3
-rw-r--r--src/doc/redirect.inc3
-rw-r--r--src/doc/robots.txt2
-rw-r--r--src/doc/rustc-dev-guide/.github/workflows/ci.yml2
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/about-this-guide.md2
-rw-r--r--src/doc/rustc-dev-guide/src/appendix/code-index.md2
-rw-r--r--src/doc/rustc-dev-guide/src/backend/debugging.md2
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md7
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-debugging.md2
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-src.md4
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-team.md2
-rw-r--r--src/doc/rustc-dev-guide/src/contributing.md30
-rw-r--r--src/doc/rustc-dev-guide/src/hir.md2
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/arm.md2
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/emscripten.md2
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/risc-v.md2
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md2
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/wasi.md2
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/wasm.md2
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/windows.md2
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md82
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc.md2
-rw-r--r--src/doc/rustc-dev-guide/src/serialization.md2
-rw-r--r--src/doc/rustc-dev-guide/src/solve/caching.md2
-rw-r--r--src/doc/rustc-dev-guide/src/solve/the-solver.md2
-rw-r--r--src/doc/rustc-dev-guide/src/stabilization_guide.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/adding.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/best-practices.md8
-rw-r--r--src/doc/rustc-dev-guide/src/tests/compiletest.md15
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md52
-rw-r--r--src/doc/rustc-dev-guide/src/tests/misc.md4
-rw-r--r--src/doc/rustc-dev-guide/src/traits/chalk.md2
-rw-r--r--src/doc/rustc-dev-guide/src/type-inference.md6
-rw-r--r--src/doc/rustc-dev-guide/src/typing_parameter_envs.md73
-rw-r--r--src/doc/rustc-dev-guide/triagebot.toml1
-rw-r--r--src/doc/rustc/src/command-line-arguments/print-options.md2
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/windows-msvc.md5
-rw-r--r--src/doc/sitemap.txt4
-rw-r--r--src/doc/style-guide/src/README.md12
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md32
-rwxr-xr-xsrc/etc/htmldocck.py2
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/config.rs14
-rw-r--r--src/librustdoc/html/static/js/search.js9
-rw-r--r--src/librustdoc/html/static/js/stringdex.d.ts13
-rw-r--r--src/librustdoc/html/static/js/stringdex.js783
-rw-r--r--src/librustdoc/scrape_examples.rs7
-rw-r--r--src/stage0242
-rw-r--r--src/tools/bump-stage0/Cargo.toml2
-rw-r--r--src/tools/bump-stage0/src/main.rs6
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.cargo/config.toml7
-rw-r--r--src/tools/clippy/CHANGELOG.md6
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md14
-rw-r--r--src/tools/clippy/clippy.toml6
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs6
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml4
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_comparison.rs179
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs96
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs228
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_buffer.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs206
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs232
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs20
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs27
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs55
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs8
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/src/driver.rs3
-rw-r--r--src/tools/clippy/tests/config-consistency.rs30
-rw-r--r--src/tools/clippy/tests/no-profile-in-cargo-toml.rs34
-rw-r--r--src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_precision/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.fixed38
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.rs38
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.stderr38
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr3
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.fixed11
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.rs11
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.stderr10
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.fixed39
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.rs41
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.stderr50
-rw-r--r--src/tools/clippy/tests/ui/async_yields_async.fixed39
-rw-r--r--src/tools/clippy/tests/ui/async_yields_async.rs39
-rw-r--r--src/tools/clippy/tests/ui/async_yields_async.stderr47
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.stderr12
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.fixed167
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.rs167
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.stderr154
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed39
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs25
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr66
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.fixed55
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.rs55
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.stderr83
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.rs41
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.stderr71
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match2.stderr2
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.fixed38
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.rs41
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.stderr47
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls_derive_const.fixed25
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls_derive_const.rs32
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls_derive_const.stderr46
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed1
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.stderr44
-rw-r--r--src/tools/clippy/tests/ui/entry_unfixable.stderr5
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed45
-rw-r--r--src/tools/clippy/tests/ui/eta.rs45
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr28
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.fixed45
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.rs45
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.stderr85
-rw-r--r--src/tools/clippy/tests/ui/float_equality_without_abs.rs14
-rw-r--r--src/tools/clippy/tests/ui/float_equality_without_abs.stderr18
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.fixed41
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.rs51
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.stderr25
-rw-r--r--src/tools/clippy/tests/ui/infinite_loops.rs15
-rw-r--r--src/tools/clippy/tests/ui/infinite_loops.stderr12
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.stderr30
-rw-r--r--src/tools/clippy/tests/ui/map_identity.fixed20
-rw-r--r--src/tools/clippy/tests/ui/map_identity.rs16
-rw-r--r--src/tools/clippy/tests/ui/map_identity.stderr66
-rw-r--r--src/tools/clippy/tests/ui/missing_inline.rs7
-rw-r--r--src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.rs29
-rw-r--r--src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.stderr36
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.fixed170
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.rs152
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.stderr76
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_unfixable.rs19
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr38
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.rs32
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.stderr26
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs2
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.stderr50
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed9
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs9
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr18
-rw-r--r--src/tools/clippy/tests/ui/or_then_unwrap.fixed6
-rw-r--r--src/tools/clippy/tests/ui/or_then_unwrap.rs6
-rw-r--r--src/tools/clippy/tests/ui/or_then_unwrap.stderr10
-rw-r--r--src/tools/clippy/tests/ui/panicking_macros.rs15
-rw-r--r--src/tools/clippy/tests/ui/panicking_macros.stderr46
-rw-r--r--src/tools/clippy/tests/ui/print_literal.fixed13
-rw-r--r--src/tools/clippy/tests/ui/print_literal.rs14
-rw-r--r--src/tools/clippy/tests/ui/print_literal.stderr38
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.fixed6
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.rs6
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.stderr8
-rw-r--r--src/tools/clippy/tests/ui/ptr_cast_constness.fixed6
-rw-r--r--src/tools/clippy/tests/ui/ptr_cast_constness.rs6
-rw-r--r--src/tools/clippy/tests/ui/ptr_cast_constness.stderr8
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.fixed5
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.rs5
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.fixed11
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.rs11
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.stderr16
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed7
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs7
-rw-r--r--src/tools/clippy/tests/ui/unit_cmp.rs17
-rw-r--r--src/tools/clippy/tests/ui/unit_cmp.stderr20
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_clone.stderr12
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.fixed25
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.rs25
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.stderr54
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2021.fixed27
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2021.stderr6
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2024.fixed29
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.rs29
-rw-r--r--src/tools/clippy/tests/ui/unwrap_in_result.rs70
-rw-r--r--src/tools/clippy/tests/ui/unwrap_in_result.stderr132
-rw-r--r--src/tools/clippy/tests/ui/vec.fixed9
-rw-r--r--src/tools/clippy/tests/ui/vec.rs9
-rw-r--r--src/tools/clippy/tests/ui/vec.stderr8
-rw-r--r--src/tools/clippy/triagebot.toml7
-rw-r--r--src/tools/compiletest/src/common.rs9
-rw-r--r--src/tools/compiletest/src/directives.rs2
-rw-r--r--src/tools/compiletest/src/executor.rs88
-rw-r--r--src/tools/compiletest/src/lib.rs28
-rw-r--r--src/tools/compiletest/src/output_capture.rs52
-rw-r--r--src/tools/compiletest/src/runtest.rs96
-rw-r--r--src/tools/compiletest/src/runtest/codegen_units.rs30
-rw-r--r--src/tools/compiletest/src/runtest/compute_diff.rs7
-rw-r--r--src/tools/compiletest/src/runtest/crashes.rs8
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs20
-rw-r--r--src/tools/compiletest/src/runtest/incremental.rs2
-rw-r--r--src/tools/compiletest/src/runtest/mir_opt.rs2
-rw-r--r--src/tools/compiletest/src/runtest/run_make.rs11
-rw-r--r--src/tools/compiletest/src/runtest/rustdoc_json.rs4
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs8
-rw-r--r--src/tools/compiletest/src/util.rs2
-rw-r--r--src/tools/miri/.github/workflows/ci.yml5
-rw-r--r--src/tools/miri/CONTRIBUTING.md6
-rw-r--r--src/tools/miri/Cargo.lock4
-rw-r--r--src/tools/miri/Cargo.toml2
-rw-r--r--src/tools/miri/README.md6
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock4
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs39
-rw-r--r--src/tools/miri/doc/img/perfetto_aggregate_statistics.pngbin0 -> 77886 bytes
-rw-r--r--src/tools/miri/doc/img/perfetto_aggregate_statistics_sql.pngbin0 -> 181156 bytes
-rw-r--r--src/tools/miri/doc/img/perfetto_span.pngbin0 -> 165716 bytes
-rw-r--r--src/tools/miri/doc/img/perfetto_subname_statistics.pngbin0 -> 102585 bytes
-rw-r--r--src/tools/miri/doc/img/perfetto_timeline.pngbin0 -> 613708 bytes
-rw-r--r--src/tools/miri/doc/img/perfetto_visualize_argument_values.pngbin0 -> 68014 bytes
-rw-r--r--src/tools/miri/doc/img/perfetto_visualize_argument_values_misbehaving.pngbin0 -> 68856 bytes
-rw-r--r--src/tools/miri/doc/img/perfetto_visualize_argument_values_sql.pngbin0 -> 261657 bytes
-rw-r--r--src/tools/miri/doc/tracing.md292
-rw-r--r--src/tools/miri/etc/rust_analyzer_zed.json41
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/log/mod.rs1
-rw-r--r--src/tools/miri/src/bin/log/tracing_chrome.rs177
-rw-r--r--src/tools/miri/src/bin/log/tracing_chrome_instant.rs183
-rw-r--r--src/tools/miri/src/bin/miri.rs6
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs225
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs17
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs2
-rw-r--r--src/tools/miri/src/eval.rs66
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs200
-rw-r--r--src/tools/miri/src/lib.rs11
-rw-r--r--src/tools/miri/src/machine.rs81
-rw-r--r--src/tools/miri/src/math.rs323
-rw-r--r--src/tools/miri/src/shims/files.rs12
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs210
-rw-r--r--src/tools/miri/src/shims/native_lib/ffi.rs46
-rw-r--r--src/tools/miri/src/shims/native_lib/mod.rs307
-rw-r--r--src/tools/miri/src/shims/native_lib/trace/child.rs30
-rw-r--r--src/tools/miri/src/shims/native_lib/trace/parent.rs82
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs56
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/eventfd.rs5
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs8
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs8
-rw-r--r--src/tools/miri/tests/deps/Cargo.lock4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/funnel_shl.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/funnel_shl.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/funnel_shr.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/funnel_shr.stderr15
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs9
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.stderr21
-rw-r--r--src/tools/miri/tests/native-lib/aggregate_arguments.c52
-rw-r--r--src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.rs23
-rw-r--r--src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.stderr28
-rw-r--r--src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs19
-rw-r--r--src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr14
-rw-r--r--src/tools/miri/tests/native-lib/fail/uninit_struct.rs27
-rw-r--r--src/tools/miri/tests/native-lib/fail/uninit_struct.stderr15
-rw-r--r--src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs52
-rw-r--r--src/tools/miri/tests/native-lib/pass/ptr_read_access.rs1
-rw-r--r--src/tools/miri/tests/pass-dep/shims/windows-fs.rs47
-rw-r--r--src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs22
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync.rs3
-rw-r--r--src/tools/miri/tests/pass/float.rs166
-rw-r--r--src/tools/miri/tests/pass/float_extra_rounding_error.rs31
-rw-r--r--src/tools/miri/tests/pass/intrinsics/integer.rs8
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs4
-rw-r--r--src/tools/miri/tests/pass/shims/x86/rounding-error.rs37
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs10
-rw-r--r--src/tools/miri/tests/ui.rs1
-rw-r--r--src/tools/miri/tests/utils/libc.rs5
-rw-r--r--src/tools/run-make-support/src/external_deps/cargo.rs14
-rw-r--r--src/tools/run-make-support/src/lib.rs5
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs20
-rw-r--r--src/tools/rustdoc-gui/.eslintrc.js96
-rw-r--r--src/tools/rustdoc-gui/tester.js309
-rw-r--r--src/tools/tidy/src/deps.rs2
-rw-r--r--src/tools/tidy/src/extra_checks/mod.rs22
-rw-r--r--src/tools/tidy/src/extra_checks/rustdoc_js.rs28
-rw-r--r--src/tools/tidy/src/triagebot.rs7
-rw-r--r--src/tools/unicode-table-generator/src/cascading_map.rs1
-rw-r--r--src/tools/unicode-table-generator/src/main.rs3
-rw-r--r--src/tools/unicode-table-generator/src/raw_emitter.rs1
-rw-r--r--src/tools/unicode-table-generator/src/skiplist.rs2
-rw-r--r--tests/assembly-llvm/breakpoint.rs1
-rw-r--r--tests/assembly-llvm/loongarch-float-struct-abi.rs134
-rw-r--r--tests/assembly-llvm/simd/reduce-fadd-unordered.rs1
-rw-r--r--tests/auxiliary/minicore.rs9
-rw-r--r--tests/codegen-llvm/amdgpu-addrspacecast.rs9
-rw-r--r--tests/codegen-llvm/cast-target-abi.rs52
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs5
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs7
-rw-r--r--tests/codegen-llvm/default-visibility.rs1
-rw-r--r--tests/codegen-llvm/gpu-kernel-abi.rs5
-rw-r--r--tests/codegen-llvm/loongarch-abi/cast-local-large-enough.rs44
-rw-r--r--tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/memory-track-origins.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/memtag-attr-check.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/safestack-attr-check.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/sanitizer-recover.rs2
-rw-r--r--tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir18
-rw-r--r--tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-abort.diff13
-rw-r--r--tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff13
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/gvn_overlapping.fields.GVN.diff14
-rw-r--r--tests/mir-opt/gvn_overlapping.rs42
-rw-r--r--tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff19
-rw-r--r--tests/mir-opt/nrvo_miscompile_111005.rs6
-rw-r--r--tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir4
-rw-r--r--tests/run-make-cargo/apple-slow-tls/rmake.rs (renamed from tests/run-make/apple-slow-tls/rmake.rs)0
-rw-r--r--tests/run-make-cargo/apple-slow-tls/tls_test/Cargo.toml (renamed from tests/run-make/apple-slow-tls/tls_test/Cargo.toml)0
-rw-r--r--tests/run-make-cargo/apple-slow-tls/tls_test/src/main.rs (renamed from tests/run-make/apple-slow-tls/tls_test/src/main.rs)0
-rw-r--r--tests/run-make-cargo/compiler-builtins/Cargo.toml (renamed from tests/run-make/compiler-builtins/Cargo.toml)0
-rw-r--r--tests/run-make-cargo/compiler-builtins/lib.rs (renamed from tests/run-make/compiler-builtins/lib.rs)0
-rw-r--r--tests/run-make-cargo/compiler-builtins/rmake.rs (renamed from tests/run-make/compiler-builtins/rmake.rs)0
-rw-r--r--tests/run-make-cargo/rustc-crates-on-stable/rmake.rs (renamed from tests/run-make/rustc-crates-on-stable/rmake.rs)0
-rw-r--r--tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/Cargo.toml (renamed from tests/run-make/rustdoc-scrape-examples-paths/foo/Cargo.toml)0
-rw-r--r--tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/examples/complex.rs (renamed from tests/run-make/rustdoc-scrape-examples-paths/foo/examples/complex.rs)0
-rw-r--r--tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/examples/tester.rs (renamed from tests/run-make/rustdoc-scrape-examples-paths/foo/examples/tester.rs)0
-rw-r--r--tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/src/lib.rs (renamed from tests/run-make/rustdoc-scrape-examples-paths/foo/src/lib.rs)0
-rw-r--r--tests/run-make-cargo/rustdoc-scrape-examples-paths/rmake.rs (renamed from tests/run-make/rustdoc-scrape-examples-paths/rmake.rs)0
-rw-r--r--tests/run-make-cargo/thumb-none-cortex-m/rmake.rs (renamed from tests/run-make/thumb-none-cortex-m/rmake.rs)2
-rw-r--r--tests/run-make-cargo/thumb-none-qemu/example/.cargo/config.toml (renamed from tests/run-make/thumb-none-qemu/example/.cargo/config.toml)0
-rw-r--r--tests/run-make-cargo/thumb-none-qemu/example/Cargo.lock (renamed from tests/run-make/thumb-none-qemu/example/Cargo.lock)0
-rw-r--r--tests/run-make-cargo/thumb-none-qemu/example/Cargo.toml (renamed from tests/run-make/thumb-none-qemu/example/Cargo.toml)0
-rw-r--r--tests/run-make-cargo/thumb-none-qemu/example/memory.x (renamed from tests/run-make/thumb-none-qemu/example/memory.x)0
-rw-r--r--tests/run-make-cargo/thumb-none-qemu/example/src/main.rs (renamed from tests/run-make/thumb-none-qemu/example/src/main.rs)0
-rw-r--r--tests/run-make-cargo/thumb-none-qemu/rmake.rs (renamed from tests/run-make/thumb-none-qemu/rmake.rs)0
-rw-r--r--tests/run-make-cargo/uefi-qemu/rmake.rs (renamed from tests/run-make/uefi-qemu/rmake.rs)0
-rw-r--r--tests/run-make-cargo/uefi-qemu/uefi_qemu_test/Cargo.lock (renamed from tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.lock)0
-rw-r--r--tests/run-make-cargo/uefi-qemu/uefi_qemu_test/Cargo.toml (renamed from tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.toml)0
-rw-r--r--tests/run-make-cargo/uefi-qemu/uefi_qemu_test/src/main.rs (renamed from tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/print.with_frame_pointers.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.with_frame_pointers.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/print.without_frame_pointers.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.without_frame_pointers.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/rmake.rs (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks)0
-rw-r--r--tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks (renamed from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks)0
-rw-r--r--tests/run-make/apple-c-available-links/foo.c22
-rw-r--r--tests/run-make/apple-c-available-links/main.rs7
-rw-r--r--tests/run-make/apple-c-available-links/rmake.rs14
-rw-r--r--tests/run-make/multiline-args-value/cfg-frontmatter.stderr4
-rw-r--r--tests/run-make/multiline-args-value/cfg-shebang.stderr3
-rw-r--r--tests/run-make/multiline-args-value/check-cfg-frontmatter.stderr7
-rw-r--r--tests/run-make/multiline-args-value/check-cfg-shebang.stderr6
-rw-r--r--tests/run-make/multiline-args-value/rmake.rs51
-rw-r--r--tests/run-make/rustdoc-dep-info/rmake.rs12
-rw-r--r--tests/run-make/rustdoc-search-load-itemtype/bar.rs27
-rw-r--r--tests/run-make/rustdoc-search-load-itemtype/baz.rs3
-rw-r--r--tests/run-make/rustdoc-search-load-itemtype/foo.rs119
-rw-r--r--tests/run-make/rustdoc-search-load-itemtype/rmake.rs21
-rw-r--r--tests/run-make/sanitizer-cdylib-link/rmake.rs2
-rw-r--r--tests/run-make/sanitizer-dylib-link/rmake.rs2
-rw-r--r--tests/run-make/sanitizer-staticlib-link/rmake.rs2
-rw-r--r--tests/run-make/separate-link-fail/rmake.rs2
-rw-r--r--tests/rustdoc-gui/scrape-examples-ice-links.goml2
-rw-r--r--tests/rustdoc-gui/src/scrape_examples_ice/empty.html1
-rw-r--r--tests/rustdoc-gui/src/scrape_examples_ice/extra.html1
-rw-r--r--tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs2
-rw-r--r--tests/rustdoc/sanitizer-option.rs2
-rw-r--r--tests/ui/asm/global-asm-isnt-really-a-mir-body.rs2
-rw-r--r--tests/ui/c-variadic/issue-86053-1.stderr4
-rw-r--r--tests/ui/c-variadic/no-closure.rs17
-rw-r--r--tests/ui/c-variadic/no-closure.stderr35
-rw-r--r--tests/ui/c-variadic/valid.rs29
-rw-r--r--tests/ui/codegen/empty-static-libs-issue-108825.rs2
-rw-r--r--tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr4
-rw-r--r--tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr4
-rw-r--r--tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr4
-rw-r--r--tests/ui/const-ptr/forbidden_slices.stderr26
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr2
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.32bit.stderr100
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.64bit.stderr100
-rw-r--r--tests/ui/consts/const-eval/transmute-const.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-enum.stderr10
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr12
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr12
-rw-r--r--tests/ui/consts/const-eval/ub-int-array.stderr6
-rw-r--r--tests/ui/consts/const-eval/ub-nonnull.stderr12
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.stderr18
-rw-r--r--tests/ui/consts/const-eval/ub-uninhabit.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-upvars.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-upvars.64bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.stderr46
-rw-r--r--tests/ui/consts/const-eval/union-ub.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/union-ub.64bit.stderr2
-rw-r--r--tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr4
-rw-r--r--tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr10
-rw-r--r--tests/ui/consts/const_refs_to_static_fail_invalid.stderr2
-rw-r--r--tests/ui/consts/dangling-alloc-id-ice.stderr2
-rw-r--r--tests/ui/consts/dangling-zst-ice-issue-126393.stderr2
-rw-r--r--tests/ui/consts/interior-mut-const-via-union.32bit.stderr2
-rw-r--r--tests/ui/consts/interior-mut-const-via-union.64bit.stderr2
-rw-r--r--tests/ui/consts/issue-17718-const-bad-values.stderr2
-rw-r--r--tests/ui/consts/issue-63952.32bit.stderr2
-rw-r--r--tests/ui/consts/issue-63952.64bit.stderr2
-rw-r--r--tests/ui/consts/issue-79690.64bit.stderr2
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references.stderr16
-rw-r--r--tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr8
-rw-r--r--tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr8
-rw-r--r--tests/ui/consts/validate_never_arrays.stderr6
-rw-r--r--tests/ui/crate-loading/invalid-rlib.rs3
-rw-r--r--tests/ui/crate-loading/invalid-rlib.stderr11
-rw-r--r--tests/ui/drop/if-let-super-let.rs112
-rw-r--r--tests/ui/error-emitter/multiline-removal-suggestion.svg364
-rw-r--r--tests/ui/feature-gates/feature-gate-target-feature-inline-always.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-target-feature-inline-always.stderr13
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs24
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr262
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed8
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs8
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr25
-rw-r--r--tests/ui/impl-trait/non-defining-uses/ice-issue-146191.current.stderr29
-rw-r--r--tests/ui/impl-trait/non-defining-uses/ice-issue-146191.next.stderr17
-rw-r--r--tests/ui/impl-trait/non-defining-uses/ice-issue-146191.rs15
-rw-r--r--tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr22
-rw-r--r--tests/ui/limits/huge-array-simple-64.full-debuginfo.stderr (renamed from tests/ui/limits/huge-array-simple-64.stderr)2
-rw-r--r--tests/ui/limits/huge-array-simple-64.no-debuginfo.stderr8
-rw-r--r--tests/ui/limits/huge-array-simple-64.rs5
-rw-r--r--tests/ui/limits/huge-array.full-debuginfo.stderr (renamed from tests/ui/limits/huge-array.stderr)2
-rw-r--r--tests/ui/limits/huge-array.no-debuginfo.stderr8
-rw-r--r--tests/ui/limits/huge-array.rs5
-rw-r--r--tests/ui/limits/issue-15919-64.full-debuginfo.stderr (renamed from tests/ui/limits/issue-15919-64.stderr)2
-rw-r--r--tests/ui/limits/issue-15919-64.no-debuginfo.stderr8
-rw-r--r--tests/ui/limits/issue-15919-64.rs5
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs2
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr2
-rw-r--r--tests/ui/linking/mixed-allocator-shim.rs16
-rw-r--r--tests/ui/lint/improper-ctypes/allow-phantomdata-in-ffi.rs (renamed from tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-113436-1.rs (renamed from tests/ui/lint/lint-ctypes-113436-1.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-113436-1.stderr (renamed from tests/ui/lint/lint-ctypes-113436-1.stderr)10
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73249-2.rs (renamed from tests/ui/lint/lint-ctypes-73249-2.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73249-2.stderr (renamed from tests/ui/lint/lint-ctypes-73249-2.stderr)4
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73249-3.rs (renamed from tests/ui/lint/lint-ctypes-73249-3.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73249-3.stderr (renamed from tests/ui/lint/lint-ctypes-73249-3.stderr)4
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73249-5.rs (renamed from tests/ui/lint/lint-ctypes-73249-5.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73249-5.stderr (renamed from tests/ui/lint/lint-ctypes-73249-5.stderr)4
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73251-1.rs (renamed from tests/ui/lint/lint-ctypes-73251-1.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73251-1.stderr (renamed from tests/ui/lint/lint-ctypes-73251-1.stderr)4
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73251-2.rs (renamed from tests/ui/lint/lint-ctypes-73251-2.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-73251-2.stderr (renamed from tests/ui/lint/lint-ctypes-73251-2.stderr)4
-rw-r--r--tests/ui/lint/improper-ctypes/lint-94223.rs (renamed from tests/ui/lint/lint-ctypes-94223.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-94223.stderr (renamed from tests/ui/lint/lint-ctypes-94223.stderr)34
-rw-r--r--tests/ui/lint/improper-ctypes/lint-cstr.rs (renamed from tests/ui/lint/lint-ctypes-cstr.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-cstr.stderr (renamed from tests/ui/lint/lint-ctypes-cstr.stderr)20
-rw-r--r--tests/ui/lint/improper-ctypes/lint-ctypes.rs (renamed from tests/ui/lint/lint-ctypes.rs)1
-rw-r--r--tests/ui/lint/improper-ctypes/lint-ctypes.stderr (renamed from tests/ui/lint/lint-ctypes.stderr)41
-rw-r--r--tests/ui/lint/improper-ctypes/lint-enum.rs (renamed from tests/ui/lint/lint-ctypes-enum.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-enum.stderr (renamed from tests/ui/lint/lint-ctypes-enum.stderr)50
-rw-r--r--tests/ui/lint/improper-ctypes/lint-fn.rs (renamed from tests/ui/lint/lint-ctypes-fn.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-fn.stderr (renamed from tests/ui/lint/lint-ctypes-fn.stderr)40
-rw-r--r--tests/ui/lint/improper-ctypes/lint-non-recursion-limit.rs (renamed from tests/ui/lint/lint-ctypes-non-recursion-limit.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.rs (renamed from tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.stderr (renamed from tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr)4
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-113436.rs (renamed from tests/ui/lint/lint-ctypes-113436.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-113900.rs (renamed from tests/ui/lint/lint-ctypes-113900.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-134060.rs (renamed from tests/ui/lint/improper_ctypes_definitions_ice_134060.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-134060.stderr (renamed from tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr)2
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-66202.rs (renamed from tests/ui/lint/lint-ctypes-66202.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-73249-1.rs (renamed from tests/ui/lint/lint-ctypes-73249-1.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-73249-4.rs (renamed from tests/ui/lint/lint-ctypes-73249-4.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-73249.rs (renamed from tests/ui/lint/lint-ctypes-73249.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-73251.rs (renamed from tests/ui/lint/lint-ctypes-73251.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/mustpass-73747.rs (renamed from tests/ui/lint/lint-ctypes-73747.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/repr-rust-is-undefined.rs (renamed from tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs)0
-rw-r--r--tests/ui/lint/improper-ctypes/repr-rust-is-undefined.stderr (renamed from tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr)0
-rw-r--r--tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr32
-rw-r--r--tests/ui/lint/unused/unused-attr-duplicate.stderr52
-rw-r--r--tests/ui/lint/unused/unused-attr-macro-rules.stderr35
-rw-r--r--tests/ui/lto/issue-100772.rs2
-rw-r--r--tests/ui/lto/lto-global-allocator.rs19
-rw-r--r--tests/ui/or-patterns/binding-typo-2.rs122
-rw-r--r--tests/ui/or-patterns/binding-typo-2.stderr254
-rw-r--r--tests/ui/or-patterns/binding-typo.fixed32
-rw-r--r--tests/ui/or-patterns/binding-typo.rs32
-rw-r--r--tests/ui/or-patterns/binding-typo.stderr31
-rw-r--r--tests/ui/or-patterns/missing-bindings.stderr81
-rw-r--r--tests/ui/parser/expr-as-stmt-2.rs23
-rw-r--r--tests/ui/parser/expr-as-stmt-2.stderr156
-rw-r--r--tests/ui/parser/expr-as-stmt.fixed11
-rw-r--r--tests/ui/parser/expr-as-stmt.rs9
-rw-r--r--tests/ui/parser/expr-as-stmt.stderr78
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.rs12
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.stderr91
-rw-r--r--tests/ui/pattern/at-in-struct-patterns.rs2
-rw-r--r--tests/ui/pattern/at-in-struct-patterns.stderr2
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr12
-rw-r--r--tests/ui/privacy/suggest-box-new.rs3
-rw-r--r--tests/ui/privacy/suggest-box-new.stderr32
-rw-r--r--tests/ui/privacy/suggest-new-projection-ice.rs19
-rw-r--r--tests/ui/privacy/suggest-new-projection-ice.stderr10
-rw-r--r--tests/ui/recursion_limit/empty.rs8
-rw-r--r--tests/ui/recursion_limit/empty.stderr12
-rw-r--r--tests/ui/recursion_limit/invalid_digit.rs8
-rw-r--r--tests/ui/recursion_limit/invalid_digit.stderr12
-rw-r--r--tests/ui/recursion_limit/invalid_digit_type.stderr8
-rw-r--r--tests/ui/recursion_limit/invalid_macro.rs2
-rw-r--r--tests/ui/recursion_limit/invalid_macro.stderr8
-rw-r--r--tests/ui/recursion_limit/no-value.stderr3
-rw-r--r--tests/ui/recursion_limit/overflow.rs3
-rw-r--r--tests/ui/recursion_limit/overflow.stderr12
-rw-r--r--tests/ui/resolve/resolve-inconsistent-names.rs4
-rw-r--r--tests/ui/resolve/resolve-inconsistent-names.stderr20
-rw-r--r--tests/ui/sanitizer/address.rs2
-rw-r--r--tests/ui/sanitizer/asan_odr_windows.rs2
-rw-r--r--tests/ui/sanitizer/badfree.rs2
-rw-r--r--tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs2
-rw-r--r--tests/ui/sanitizer/cfi/async-closures.rs2
-rw-r--r--tests/ui/sanitizer/cfi/can-reveal-opaques.rs2
-rw-r--r--tests/ui/sanitizer/cfi/closures.rs2
-rw-r--r--tests/ui/sanitizer/cfi/complex-receiver.rs2
-rw-r--r--tests/ui/sanitizer/cfi/coroutine.rs1
-rw-r--r--tests/ui/sanitizer/cfi/drop-in-place.rs1
-rw-r--r--tests/ui/sanitizer/cfi/drop-no-principal.rs2
-rw-r--r--tests/ui/sanitizer/cfi/fn-ptr.rs1
-rw-r--r--tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs1
-rw-r--r--tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs2
-rw-r--r--tests/ui/sanitizer/cfi/self-ref.rs2
-rw-r--r--tests/ui/sanitizer/cfi/sized-associated-ty.rs2
-rw-r--r--tests/ui/sanitizer/cfi/supertraits.rs2
-rw-r--r--tests/ui/sanitizer/cfi/transparent-has-regions.rs2
-rw-r--r--tests/ui/sanitizer/cfi/virtual-auto.rs2
-rw-r--r--tests/ui/sanitizer/dataflow.rs2
-rw-r--r--tests/ui/sanitizer/hwaddress.rs2
-rw-r--r--tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs2
-rw-r--r--tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs2
-rw-r--r--tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs2
-rw-r--r--tests/ui/sanitizer/kcfi-mangling.rs2
-rw-r--r--tests/ui/sanitizer/leak.rs2
-rw-r--r--tests/ui/sanitizer/memory-eager.rs2
-rw-r--r--tests/ui/sanitizer/memory-passing.rs2
-rw-r--r--tests/ui/sanitizer/memory.rs2
-rw-r--r--tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs2
-rw-r--r--tests/ui/sanitizer/thread.rs2
-rw-r--r--tests/ui/sanitizer/use-after-scope.rs2
-rw-r--r--tests/ui/span/issue-39698.stderr24
-rw-r--r--tests/ui/statics/mutable_memory_validation.stderr2
-rw-r--r--tests/ui/suggestions/multi-suggestion.ascii.stderr2
-rw-r--r--tests/ui/suggestions/multi-suggestion.unicode.stderr2
-rw-r--r--tests/ui/target-feature/inline-always.aarch64.stderr60
-rw-r--r--tests/ui/target-feature/inline-always.rs54
-rw-r--r--tests/ui/target-feature/invalid-attribute.rs2
-rw-r--r--tests/ui/target-feature/invalid-attribute.stderr28
-rw-r--r--tests/ui/target_modifiers/auxiliary/kcfi-normalize-ints.rs7
-rw-r--r--tests/ui/target_modifiers/auxiliary/no-sanitizers.rs6
-rw-r--r--tests/ui/target_modifiers/auxiliary/safestack-and-kcfi.rs10
-rw-r--r--tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.rs18
-rw-r--r--tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_flag.stderr13
-rw-r--r--tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_sanitizer.stderr13
-rw-r--r--tests/ui/target_modifiers/sanitizers-good-for-inconsistency.rs19
-rw-r--r--tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_both.stderr13
-rw-r--r--tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_kcfi.stderr13
-rw-r--r--tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_safestack.stderr13
-rw-r--r--tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.rs23
-rw-r--r--tests/ui/traits/bound/suggest-complex-bound-on-method.fixed23
-rw-r--r--tests/ui/traits/bound/suggest-complex-bound-on-method.rs23
-rw-r--r--tests/ui/traits/bound/suggest-complex-bound-on-method.stderr22
-rw-r--r--tests/ui/traits/const-traits/constructor-const-fn.rs2
-rw-r--r--tests/ui/traits/const-traits/reservation-impl-ice.rs2
-rw-r--r--tests/ui/traits/const-traits/reservation-impl-ice.stderr4
-rw-r--r--tests/ui/type-alias-impl-trait/fallback.rs29
-rw-r--r--tests/ui/type-alias-impl-trait/fallback.stderr20
-rw-r--r--tests/ui/type/pattern_types/validity.stderr10
-rw-r--r--tests/ui/type/type-name-basic.rs15
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs2
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr2
-rw-r--r--triagebot.toml20
993 files changed, 18984 insertions, 8958 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a8df53f3a41..2053ad81441 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -336,7 +336,7 @@ dependencies = [
  "curl",
  "indexmap",
  "serde",
- "toml 0.7.8",
+ "toml 0.8.23",
 ]
 
 [[package]]
@@ -3204,9 +3204,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.9"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdb13874a0e55baf4ac3d49d38206aecb31a55b75d6c4d04fd850b53942c8cc8"
+checksum = "3b881c015c729b43105bbd3702a9bdecee28fafaa21126d1d62e454ec011a4b7"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -4022,6 +4022,7 @@ dependencies = [
 name = "rustc_lint"
 version = "0.0.0"
 dependencies = [
+ "bitflags",
  "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
@@ -4072,7 +4073,6 @@ name = "rustc_log"
 version = "0.0.0"
 dependencies = [
  "tracing",
- "tracing-core",
  "tracing-subscriber",
  "tracing-tree",
 ]
@@ -4409,7 +4409,6 @@ dependencies = [
  "rustc_middle",
  "rustc_query_system",
  "rustc_serialize",
- "rustc_session",
  "rustc_span",
  "tracing",
 ]
@@ -4681,6 +4680,7 @@ dependencies = [
 name = "rustc_type_ir"
 version = "0.0.0"
 dependencies = [
+ "arrayvec",
  "bitflags",
  "derive-where",
  "ena",
@@ -5152,9 +5152,9 @@ dependencies = [
 
 [[package]]
 name = "stringdex"
-version = "0.0.1-alpha4"
+version = "0.0.1-alpha9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2841fd43df5b1ff1b042e167068a1fe9b163dc93041eae56ab2296859013a9a0"
+checksum = "7081029913fd7d591c0112182aba8c98ae886b4f12edb208130496cd17dc3c15"
 dependencies = [
  "stacker",
 ]
@@ -5518,11 +5518,10 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
 
 [[package]]
 name = "tracing"
-version = "0.1.37"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
 dependencies = [
- "cfg-if",
  "pin-project-lite",
  "tracing-attributes",
  "tracing-core",
@@ -5541,9 +5540,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.30"
+version = "0.1.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
 dependencies = [
  "once_cell",
  "valuable",
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 16fd9241a17..eac93957797 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -856,6 +856,9 @@
 # as libstd features, this option can also be used to configure features such as optimize_for_size.
 #rust.std-features = ["panic_unwind"]
 
+# Trigger a `DebugBreak` after an internal compiler error during bootstrap on Windows
+#rust.break-on-ice = true
+
 # =============================================================================
 # Distribution options
 #
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index ea98bebd305..6dc6d1026f6 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -22,8 +22,7 @@ pub enum CommentKind {
     Block,
 }
 
-// This type must not implement `Hash` due to the unusual `PartialEq` impl below.
-#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
 pub enum InvisibleOrigin {
     // From the expansion of a metavariable in a declarative macro.
     MetaVar(MetaVarKind),
@@ -45,20 +44,6 @@ impl InvisibleOrigin {
     }
 }
 
-impl PartialEq for InvisibleOrigin {
-    #[inline]
-    fn eq(&self, _other: &InvisibleOrigin) -> bool {
-        // When we had AST-based nonterminals we couldn't compare them, and the
-        // old `Nonterminal` type had an `eq` that always returned false,
-        // resulting in this restriction:
-        // https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment
-        // This `eq` emulates that behaviour. We could consider lifting this
-        // restriction now but there are still cases involving invisible
-        // delimiters that make it harder than it first appears.
-        false
-    }
-}
-
 /// Annoyingly similar to `NonterminalKind`, but the slight differences are important.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
 pub enum MetaVarKind {
@@ -142,7 +127,8 @@ impl Delimiter {
         }
     }
 
-    // This exists because `InvisibleOrigin`s should be compared. It is only used for assertions.
+    // This exists because `InvisibleOrigin`s should not be compared. It is only used for
+    // assertions.
     pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
         match (self, other) {
             (Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 6133cc3548b..538918a890d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -665,46 +665,42 @@ impl<'a> AstValidator<'a> {
     /// - Non-const
     /// - Either foreign, or free and `unsafe extern "C"` semantically
     fn check_c_variadic_type(&self, fk: FnKind<'a>) {
-        let variadic_spans: Vec<_> = fk
-            .decl()
-            .inputs
-            .iter()
-            .filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
-            .map(|arg| arg.span)
-            .collect();
+        // `...` is already rejected when it is not the final parameter.
+        let variadic_param = match fk.decl().inputs.last() {
+            Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
+            _ => return,
+        };
 
-        if variadic_spans.is_empty() {
-            return;
-        }
+        let FnKind::Fn(fn_ctxt, _, Fn { sig, .. }) = fk else {
+            // Unreachable because the parser already rejects `...` in closures.
+            unreachable!("C variable argument list cannot be used in closures")
+        };
 
-        if let Some(header) = fk.header()
-            && let Const::Yes(const_span) = header.constness
-        {
-            let mut spans = variadic_spans.clone();
-            spans.push(const_span);
+        // C-variadics are not yet implemented in const evaluation.
+        if let Const::Yes(const_span) = sig.header.constness {
             self.dcx().emit_err(errors::ConstAndCVariadic {
-                spans,
+                spans: vec![const_span, variadic_param.span],
                 const_span,
-                variadic_spans: variadic_spans.clone(),
+                variadic_span: variadic_param.span,
             });
         }
 
-        match (fk.ctxt(), fk.header()) {
-            (Some(FnCtxt::Foreign), _) => return,
-            (Some(FnCtxt::Free), Some(header)) => match header.ext {
+        match fn_ctxt {
+            FnCtxt::Foreign => return,
+            FnCtxt::Free => match sig.header.ext {
                 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
                 | Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _)
                 | Extern::Implicit(_)
-                    if matches!(header.safety, Safety::Unsafe(_)) =>
+                    if matches!(sig.header.safety, Safety::Unsafe(_)) =>
                 {
                     return;
                 }
                 _ => {}
             },
-            _ => {}
+            FnCtxt::Assoc(_) => {}
         };
 
-        self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans });
+        self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span });
     }
 
     fn check_item_named(&self, ident: Ident, kind: &str) {
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ae8f056cb4e..476ed27a10e 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -322,7 +322,7 @@ pub(crate) struct ExternItemAscii {
 #[diag(ast_passes_bad_c_variadic)]
 pub(crate) struct BadCVariadic {
     #[primary_span]
-    pub span: Vec<Span>,
+    pub span: Span,
 }
 
 #[derive(Diagnostic)]
@@ -656,7 +656,7 @@ pub(crate) struct ConstAndCVariadic {
     #[label(ast_passes_const)]
     pub const_span: Span,
     #[label(ast_passes_variadic)]
-    pub variadic_spans: Vec<Span>,
+    pub variadic_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index b8a748563d5..839a5d23c3b 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -151,7 +151,7 @@ attr_parsing_unrecognized_repr_hint =
 attr_parsing_unstable_cfg_target_compact =
     compact `cfg(target(..))` is experimental and subject to change
 
-attr_parsing_unstable_feature_bound_incompatible_stability = Item annotated with `#[unstable_feature_bound]` should not be stable
+attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
     .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
 
 attr_parsing_unsupported_literal_cfg_boolean =
@@ -247,3 +247,7 @@ attr_parsing_raw_dylib_only_windows =
 
 attr_parsing_whole_archive_needs_static =
     linking modifier `whole-archive` is only compatible with `static` linking kind
+
+attr_parsing_limit_invalid =
+    `limit` must be a non-negative integer
+    .label = {$error_str}
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 2fed09b85e8..d23a7ae72f8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -1,6 +1,40 @@
-use rustc_feature::AttributeType;
+use std::num::IntErrorKind;
+
+use rustc_hir::limit::Limit;
 
 use super::prelude::*;
+use crate::session_diagnostics::LimitInvalid;
+
+impl<S: Stage> AcceptContext<'_, '_, S> {
+    fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
+        let Some(limit) = nv.value_as_str() else {
+            self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+            return None;
+        };
+
+        let error_str = match limit.as_str().parse() {
+            Ok(i) => return Some(Limit::new(i)),
+            Err(e) => match e.kind() {
+                IntErrorKind::PosOverflow => "`limit` is too large",
+                IntErrorKind::Empty => "`limit` must be a non-negative integer",
+                IntErrorKind::InvalidDigit => "not a valid integer",
+                IntErrorKind::NegOverflow => {
+                    panic!(
+                        "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
+                    )
+                }
+                IntErrorKind::Zero => {
+                    panic!("zero is a valid `limit` so should have returned Ok() when parsing")
+                }
+                kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
+            },
+        };
+
+        self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
+
+        None
+    }
+}
 
 pub(crate) struct CrateNameParser;
 
@@ -11,8 +45,8 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
     const TYPE: AttributeType = AttributeType::CrateLevel;
 
-    // FIXME: crate name is allowed on all targets and ignored,
-    //        even though it should only be valid on crates of course
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -34,3 +68,111 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
         })
     }
 }
+
+pub(crate) struct RecursionLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
+    const PATH: &[Symbol] = &[sym::recursion_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
+    const TYPE: AttributeType = AttributeType::CrateLevel;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let ArgParser::NameValue(nv) = args else {
+            cx.expected_name_value(cx.attr_span, None);
+            return None;
+        };
+
+        Some(AttributeKind::RecursionLimit {
+            limit: cx.parse_limit_int(nv)?,
+            attr_span: cx.attr_span,
+            limit_span: nv.value_span,
+        })
+    }
+}
+
+pub(crate) struct MoveSizeLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
+    const PATH: &[Symbol] = &[sym::move_size_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+    const TYPE: AttributeType = AttributeType::CrateLevel;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let ArgParser::NameValue(nv) = args else {
+            cx.expected_name_value(cx.attr_span, None);
+            return None;
+        };
+
+        Some(AttributeKind::MoveSizeLimit {
+            limit: cx.parse_limit_int(nv)?,
+            attr_span: cx.attr_span,
+            limit_span: nv.value_span,
+        })
+    }
+}
+
+pub(crate) struct TypeLengthLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
+    const PATH: &[Symbol] = &[sym::type_length_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+    const TYPE: AttributeType = AttributeType::CrateLevel;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let ArgParser::NameValue(nv) = args else {
+            cx.expected_name_value(cx.attr_span, None);
+            return None;
+        };
+
+        Some(AttributeKind::TypeLengthLimit {
+            limit: cx.parse_limit_int(nv)?,
+            attr_span: cx.attr_span,
+            limit_span: nv.value_span,
+        })
+    }
+}
+
+pub(crate) struct PatternComplexityLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
+    const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+    const TYPE: AttributeType = AttributeType::CrateLevel;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let ArgParser::NameValue(nv) = args else {
+            cx.expected_name_value(cx.attr_span, None);
+            return None;
+        };
+
+        Some(AttributeKind::PatternComplexityLimit {
+            limit: cx.parse_limit_int(nv)?,
+            attr_span: cx.attr_span,
+            limit_span: nv.value_span,
+        })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
index 6aef7e7a67b..8f040ffb9d4 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
@@ -1,8 +1,7 @@
-// templates
-#[doc(hidden)]
-pub(super) use rustc_feature::{AttributeTemplate, template};
 // data structures
 #[doc(hidden)]
+pub(super) use rustc_feature::{AttributeTemplate, AttributeType, template};
+#[doc(hidden)]
 pub(super) use rustc_hir::attrs::AttributeKind;
 #[doc(hidden)]
 pub(super) use rustc_hir::lints::AttributeLintKind;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 7f5b810f244..98e86838a3a 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -24,7 +24,10 @@ use crate::attributes::codegen_attrs::{
     UsedParser,
 };
 use crate::attributes::confusables::ConfusablesParser;
-use crate::attributes::crate_level::CrateNameParser;
+use crate::attributes::crate_level::{
+    CrateNameParser, MoveSizeLimitParser, PatternComplexityLimitParser, RecursionLimitParser,
+    TypeLengthLimitParser,
+};
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::dummy::DummyParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -181,10 +184,13 @@ attribute_parsers!(
         Single<LinkOrdinalParser>,
         Single<LinkSectionParser>,
         Single<LinkageParser>,
+        Single<MoveSizeLimitParser>,
         Single<MustUseParser>,
         Single<OptimizeParser>,
         Single<PathAttributeParser>,
+        Single<PatternComplexityLimitParser>,
         Single<ProcMacroDeriveParser>,
+        Single<RecursionLimitParser>,
         Single<RustcBuiltinMacroParser>,
         Single<RustcForceInlineParser>,
         Single<RustcLayoutScalarValidRangeEnd>,
@@ -194,6 +200,7 @@ attribute_parsers!(
         Single<ShouldPanicParser>,
         Single<SkipDuringMethodDispatchParser>,
         Single<TransparencyParser>,
+        Single<TypeLengthLimitParser>,
         Single<WithoutArgs<AllowIncoherentImplParser>>,
         Single<WithoutArgs<AllowInternalUnsafeParser>>,
         Single<WithoutArgs<AsPtrParser>>,
@@ -346,7 +353,10 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
     /// must be delayed until after HIR is built. This method will take care of the details of
     /// that.
     pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
-        if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
+        if !matches!(
+            self.stage.should_emit(),
+            ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
+        ) {
             return;
         }
         let id = self.target_id;
@@ -670,20 +680,20 @@ pub enum ShouldEmit {
     ///
     /// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`.
     /// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible.
-    EarlyFatal,
+    EarlyFatal { also_emit_lints: bool },
     /// The operation will emit errors and lints.
     /// This is usually what you need.
     ErrorsAndLints,
     /// The operation will emit *not* errors and lints.
-    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
+    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
     Nothing,
 }
 
 impl ShouldEmit {
     pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed {
         match self {
-            ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(),
-            ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(),
+            ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
+            ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
             ShouldEmit::ErrorsAndLints => diag.emit(),
             ShouldEmit::Nothing => diag.delay_as_bug(),
         }
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index a9dee23bf6a..32ea9005a97 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -930,3 +930,13 @@ pub(crate) struct ImportNameTypeRaw {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(attr_parsing_limit_invalid)]
+pub(crate) struct LimitInvalid<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub value_span: Span,
+    pub error_str: &'a str,
+}
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
index 72615cb33b3..95c5366a6c8 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
@@ -503,7 +503,16 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
     let mut errors = Vec::new();
     for &(key, hidden_type) in opaque_types {
         let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else {
-            assert!(tcx.use_typing_mode_borrowck(), "non-defining use in defining scope");
+            if !tcx.use_typing_mode_borrowck() {
+                if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
+                    && alias_ty.def_id == key.def_id.to_def_id()
+                    && alias_ty.args == key.args
+                {
+                    continue;
+                } else {
+                    unreachable!("non-defining use in defining scope");
+                }
+            }
             errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
                 span: hidden_type.span,
                 opaque_type_key: key,
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 52e02c857c7..62f1cc6a893 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -121,7 +121,7 @@ rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift
 # ============================================================
 rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
 rm -r tests/run-make/strip # same
-rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source
+rm -r tests/run-make-cargo/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source
 rm -r tests/run-make/translation # same
 rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features
 rm -r tests/run-make/const-trait-stable-toolchain # same
@@ -166,5 +166,5 @@ index 073116933bd..c3e4578204d 100644
 EOF
 
 echo "[TEST] rustc test suite"
-./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
+./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,run-make-cargo,ui,incremental}
 popd
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index 3dd3fce2eec..1823aa71f40 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -1083,11 +1083,12 @@ where
 
 fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
     test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
+    test_rustc_inner(env, args, |_| Ok(false), false, "run-make-cargo")?;
     test_rustc_inner(env, args, |_| Ok(false), false, "ui")
 }
 
 fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
-    let result1 = test_rustc_inner(
+    let run_make_result = test_rustc_inner(
         env,
         args,
         retain_files_callback("tests/failing-run-make-tests.txt", "run-make"),
@@ -1095,7 +1096,15 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
         "run-make",
     );
 
-    let result2 = test_rustc_inner(
+    let run_make_cargo_result = test_rustc_inner(
+        env,
+        args,
+        retain_files_callback("tests/failing-run-make-tests.txt", "run-make-cargo"),
+        false,
+        "run-make",
+    );
+
+    let ui_result = test_rustc_inner(
         env,
         args,
         retain_files_callback("tests/failing-ui-tests.txt", "ui"),
@@ -1103,7 +1112,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
         "ui",
     );
 
-    result1.and(result2)
+    run_make_result.and(run_make_cargo_result).and(ui_result)
 }
 
 fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
@@ -1120,6 +1129,13 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
         remove_files_callback("tests/failing-run-make-tests.txt", "run-make"),
         false,
         "run-make",
+    )?;
+    test_rustc_inner(
+        env,
+        args,
+        remove_files_callback("tests/failing-run-make-tests.txt", "run-make-cargo"),
+        false,
+        "run-make-cargo",
     )
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs
index fcee6b6df62..d29bba2570f 100644
--- a/compiler/rustc_codegen_gcc/src/back/lto.rs
+++ b/compiler/rustc_codegen_gcc/src/back/lto.rs
@@ -204,7 +204,7 @@ fn fat_lto(
             let path = tmp_path.path().to_path_buf().join(&module.name);
             let path = path.to_str().expect("path");
             let context = &module.module_llvm.context;
-            let config = cgcx.config(module.kind);
+            let config = &cgcx.module_config;
             // NOTE: we need to set the optimization level here in order for LTO to do its job.
             context.set_optimization_level(to_gcc_opt_level(config.opt_level));
             context.add_command_line_option("-flto=auto");
@@ -305,12 +305,9 @@ pub(crate) fn run_thin(
     )
 }
 
-pub(crate) fn prepare_thin(
-    module: ModuleCodegen<GccContext>,
-    _emit_summary: bool,
-) -> (String, ThinBuffer) {
+pub(crate) fn prepare_thin(module: ModuleCodegen<GccContext>) -> (String, ThinBuffer) {
     let name = module.name;
-    //let buffer = ThinBuffer::new(module.module_llvm.context, true, emit_summary);
+    //let buffer = ThinBuffer::new(module.module_llvm.context, true);
     let buffer = ThinBuffer::new(&module.module_llvm.context);
     (name, buffer)
 }
@@ -650,10 +647,6 @@ impl ThinBufferMethods for ThinBuffer {
     fn data(&self) -> &[u8] {
         &[]
     }
-
-    fn thin_link_data(&self) -> &[u8] {
-        unimplemented!();
-    }
 }
 
 pub struct ThinData; //(Arc<TempDir>);
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 2d7df79ba95..f76f933cad4 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -408,11 +408,8 @@ impl WriteBackendMethods for GccCodegenBackend {
         back::write::codegen(cgcx, module, config)
     }
 
-    fn prepare_thin(
-        module: ModuleCodegen<Self::Module>,
-        emit_summary: bool,
-    ) -> (String, Self::ThinBuffer) {
-        back::lto::prepare_thin(module, emit_summary)
+    fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
+        back::lto::prepare_thin(module)
     }
 
     fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 5affb26483a..573c51a9539 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -29,8 +29,18 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
 }
 
 /// Get LLVM attribute for the provided inline heuristic.
-#[inline]
-fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {
+pub(crate) fn inline_attr<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    instance: ty::Instance<'tcx>,
+) -> Option<&'ll Attribute> {
+    // `optnone` requires `noinline`
+    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
+    let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
+        (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
+        (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
+        (inline, _) => inline,
+    };
+
     if !cx.tcx.sess.opts.unstable_opts.inline_llvm {
         // disable LLVM inlining
         return Some(AttributeKind::NoInline.create_attr(cx.llcx));
@@ -286,6 +296,19 @@ pub(crate) fn tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribu
         .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
 }
 
+/// Get the `target-features` LLVM attribute.
+pub(crate) fn target_features_attr<'ll>(
+    cx: &CodegenCx<'ll, '_>,
+    function_features: Vec<String>,
+) -> Option<&'ll Attribute> {
+    let global_features = cx.tcx.global_backend_features(()).iter().map(String::as_str);
+    let function_features = function_features.iter().map(String::as_str);
+    let target_features =
+        global_features.chain(function_features).intersperse(",").collect::<String>();
+    (!target_features.is_empty())
+        .then(|| llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features))
+}
+
 /// Get the `NonLazyBind` LLVM attribute,
 /// if the codegen options allow skipping the PLT.
 pub(crate) fn non_lazy_bind_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
@@ -346,14 +369,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         OptimizeAttr::Speed => {}
     }
 
-    // `optnone` requires `noinline`
-    let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
-        (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
-        (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
-        (inline, _) => inline,
-    };
-    to_add.extend(inline_attr(cx, inline));
-
     if cx.sess().must_emit_unwind_tables() {
         to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind));
     }
@@ -488,6 +503,14 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     let function_features =
         codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
 
+    // Apply function attributes as per usual if there are no user defined
+    // target features otherwise this will get applied at the callsite.
+    if function_features.is_empty() {
+        if let Some(inline_attr) = inline_attr(cx, instance) {
+            to_add.push(inline_attr);
+        }
+    }
+
     let function_features = function_features
         .iter()
         // Convert to LLVMFeatures and filter out unavailable ones
@@ -513,13 +536,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         }
     }
 
-    let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
-    let function_features = function_features.iter().map(|s| s.as_str());
-    let target_features: String =
-        global_features.chain(function_features).intersperse(",").collect();
-    if !target_features.is_empty() {
-        to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
-    }
+    to_add.extend(target_features_attr(cx, function_features));
 
     attributes::apply_to_llfn(llfn, Function, &to_add);
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index fc38c4f3e51..f571716d9dd 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -43,9 +43,7 @@ fn prepare_lto(
         .map(|symbol| CString::new(symbol.to_owned()).unwrap())
         .collect::<Vec<CString>>();
 
-    if cgcx.regular_module_config.instrument_coverage
-        || cgcx.regular_module_config.pgo_gen.enabled()
-    {
+    if cgcx.module_config.instrument_coverage || cgcx.module_config.pgo_gen.enabled() {
         // These are weak symbols that point to the profile version and the
         // profile name, which need to be treated as exported so LTO doesn't nix
         // them.
@@ -55,15 +53,15 @@ fn prepare_lto(
         symbols_below_threshold.extend(PROFILER_WEAK_SYMBOLS.iter().map(|&sym| sym.to_owned()));
     }
 
-    if cgcx.regular_module_config.sanitizer.contains(SanitizerSet::MEMORY) {
+    if cgcx.module_config.sanitizer.contains(SanitizerSet::MEMORY) {
         let mut msan_weak_symbols = Vec::new();
 
         // Similar to profiling, preserve weak msan symbol during LTO.
-        if cgcx.regular_module_config.sanitizer_recover.contains(SanitizerSet::MEMORY) {
+        if cgcx.module_config.sanitizer_recover.contains(SanitizerSet::MEMORY) {
             msan_weak_symbols.push(c"__msan_keep_going");
         }
 
-        if cgcx.regular_module_config.sanitizer_memory_track_origins != 0 {
+        if cgcx.module_config.sanitizer_memory_track_origins != 0 {
             msan_weak_symbols.push(c"__msan_track_origins");
         }
 
@@ -187,12 +185,9 @@ pub(crate) fn run_thin(
     thin_lto(cgcx, dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold)
 }
 
-pub(crate) fn prepare_thin(
-    module: ModuleCodegen<ModuleLlvm>,
-    emit_summary: bool,
-) -> (String, ThinBuffer) {
+pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
     let name = module.name;
-    let buffer = ThinBuffer::new(module.module_llvm.llmod(), true, emit_summary);
+    let buffer = ThinBuffer::new(module.module_llvm.llmod(), true);
     (name, buffer)
 }
 
@@ -583,7 +578,7 @@ pub(crate) fn run_pass_manager(
     thin: bool,
 ) {
     let _timer = cgcx.prof.generic_activity_with_arg("LLVM_lto_optimize", &*module.name);
-    let config = cgcx.config(module.kind);
+    let config = &cgcx.module_config;
 
     // Now we have one massive module inside of llmod. Time to run the
     // LTO-specific optimization passes that LLVM provides.
@@ -689,9 +684,9 @@ unsafe impl Send for ThinBuffer {}
 unsafe impl Sync for ThinBuffer {}
 
 impl ThinBuffer {
-    pub(crate) fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer {
+    pub(crate) fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer {
         unsafe {
-            let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary);
+            let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin);
             ThinBuffer(buffer)
         }
     }
@@ -700,21 +695,21 @@ impl ThinBuffer {
         let mut ptr = NonNull::new(ptr).unwrap();
         ThinBuffer(unsafe { ptr.as_mut() })
     }
-}
 
-impl ThinBufferMethods for ThinBuffer {
-    fn data(&self) -> &[u8] {
+    pub(crate) fn thin_link_data(&self) -> &[u8] {
         unsafe {
-            let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
-            let len = llvm::LLVMRustThinLTOBufferLen(self.0);
+            let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _;
+            let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0);
             slice::from_raw_parts(ptr, len)
         }
     }
+}
 
-    fn thin_link_data(&self) -> &[u8] {
+impl ThinBufferMethods for ThinBuffer {
+    fn data(&self) -> &[u8] {
         unsafe {
-            let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _;
-            let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0);
+            let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
+            let len = llvm::LLVMRustThinLTOBufferLen(self.0);
             slice::from_raw_parts(ptr, len)
         }
     }
@@ -745,7 +740,7 @@ pub(crate) fn optimize_thin_module(
     let module_llvm = ModuleLlvm::parse(cgcx, module_name, thin_module.data(), dcx);
     let mut module = ModuleCodegen::new_regular(thin_module.name(), module_llvm);
     // Given that the newly created module lacks a thinlto buffer for embedding, we need to re-add it here.
-    if cgcx.config(ModuleKind::Regular).embed_bitcode() {
+    if cgcx.module_config.embed_bitcode() {
         module.thin_lto_buffer = Some(thin_module.data().to_vec());
     }
     {
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 7ea2ae6673b..423f0da4878 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -837,7 +837,7 @@ pub(crate) fn codegen(
                         "LLVM_module_codegen_make_bitcode",
                         &*module.name,
                     );
-                    ThinBuffer::new(llmod, config.emit_thin_lto, false)
+                    ThinBuffer::new(llmod, config.emit_thin_lto)
                 };
                 let data = thin.data();
                 let _timer = cgcx
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 37379586d58..7d0691366e6 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1392,7 +1392,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     fn call(
         &mut self,
         llty: &'ll Type,
-        fn_attrs: Option<&CodegenFnAttrs>,
+        fn_call_attrs: Option<&CodegenFnAttrs>,
         fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
         llfn: &'ll Value,
         args: &[&'ll Value],
@@ -1409,10 +1409,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
 
         // Emit CFI pointer type membership test
-        self.cfi_type_test(fn_attrs, fn_abi, instance, llfn);
+        self.cfi_type_test(fn_call_attrs, fn_abi, instance, llfn);
 
         // Emit KCFI operand bundle
-        let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
+        let kcfi_bundle = self.kcfi_operand_bundle(fn_call_attrs, fn_abi, instance, llfn);
         if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) {
             bundles.push(kcfi_bundle);
         }
@@ -1429,6 +1429,29 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 c"".as_ptr(),
             )
         };
+
+        if let Some(instance) = instance {
+            // Attributes on the function definition being called
+            let fn_defn_attrs = self.cx.tcx.codegen_fn_attrs(instance.def_id());
+            if let Some(fn_call_attrs) = fn_call_attrs
+                && !fn_call_attrs.target_features.is_empty()
+                // If there is an inline attribute and a target feature that matches
+                // we will add the attribute to the callsite otherwise we'll omit
+                // this and not add the attribute to prevent soundness issues.
+                && let Some(inlining_rule) = attributes::inline_attr(&self.cx, instance)
+                && self.cx.tcx.is_target_feature_call_safe(
+                    &fn_call_attrs.target_features,
+                    &fn_defn_attrs.target_features,
+                )
+            {
+                attributes::apply_to_callsite(
+                    call,
+                    llvm::AttributePlace::Function,
+                    &[inlining_rule],
+                );
+            }
+        }
+
         if let Some(fn_abi) = fn_abi {
             fn_abi.apply_attrs_callsite(self, call);
         }
diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs
index 1280ab1442a..0737a18384b 100644
--- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs
@@ -193,7 +193,7 @@ fn gen_define_handling<'ll>(
     // reference) types.
     let num_ptr_types = types
         .iter()
-        .map(|&x| matches!(cx.type_kind(x), rustc_codegen_ssa::common::TypeKind::Pointer))
+        .filter(|&x| matches!(cx.type_kind(x), rustc_codegen_ssa::common::TypeKind::Pointer))
         .count();
 
     // We do not know their size anymore at this level, so hardcode a placeholder.
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 4fd6110ac4a..a69fa54a54a 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -217,6 +217,10 @@ pub(crate) unsafe fn create_module<'ll>(
             // LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010
             target_data_layout = target_data_layout.replace("n8:16", "n8")
         }
+        if sess.target.arch == "nvptx64" {
+            // LLVM 22 updated the NVPTX layout to indicate 256-bit vector load/store: https://github.com/llvm/llvm-project/pull/155198
+            target_data_layout = target_data_layout.replace("-i256:256", "");
+        }
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
@@ -849,7 +853,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
         let entry_name = self.sess().target.entry_name.as_ref();
         if self.get_declared_value(entry_name).is_none() {
-            Some(self.declare_entry_fn(
+            let llfn = self.declare_entry_fn(
                 entry_name,
                 llvm::CallConv::from_conv(
                     self.sess().target.entry_abi,
@@ -857,7 +861,13 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 ),
                 llvm::UnnamedAddr::Global,
                 fn_type,
-            ))
+            );
+            attributes::apply_to_llfn(
+                llfn,
+                llvm::AttributePlace::Function,
+                attributes::target_features_attr(self, vec![]).as_slice(),
+            );
+            Some(llfn)
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index caa3369f413..1790e212252 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -103,16 +103,17 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     unique_type_id: UniqueTypeId<'tcx>,
     array_type: Ty<'tcx>,
+    span: Span,
 ) -> DINodeCreationResult<'ll> {
     let ty::Array(element_type, len) = array_type.kind() else {
         bug!("build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", array_type)
     };
 
-    let element_type_di_node = type_di_node(cx, *element_type);
+    let element_type_di_node = spanned_type_di_node(cx, *element_type, span);
 
     return_if_di_node_created_in_meantime!(cx, unique_type_id);
 
-    let (size, align) = cx.size_and_align_of(array_type);
+    let (size, align) = cx.spanned_size_and_align_of(array_type, span);
 
     let upper_bound = len
         .try_to_target_usize(cx.tcx)
@@ -447,7 +448,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
             build_basic_type_di_node(cx, t)
         }
         ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
-        ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
+        ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span),
         ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
         ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
         ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 49d3dedbeab..85f71f331a4 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -383,7 +383,9 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             | sym::rotate_left
             | sym::rotate_right
             | sym::saturating_add
-            | sym::saturating_sub => {
+            | sym::saturating_sub
+            | sym::unchecked_funnel_shl
+            | sym::unchecked_funnel_shr => {
                 let ty = args[0].layout.ty;
                 if !ty.is_integral() {
                     tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
@@ -424,18 +426,26 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     sym::bitreverse => {
                         self.call_intrinsic("llvm.bitreverse", &[llty], &[args[0].immediate()])
                     }
-                    sym::rotate_left | sym::rotate_right => {
-                        let is_left = name == sym::rotate_left;
-                        let val = args[0].immediate();
-                        let raw_shift = args[1].immediate();
-                        // rotate = funnel shift with first two args the same
+                    sym::rotate_left
+                    | sym::rotate_right
+                    | sym::unchecked_funnel_shl
+                    | sym::unchecked_funnel_shr => {
+                        let is_left = name == sym::rotate_left || name == sym::unchecked_funnel_shl;
+                        let lhs = args[0].immediate();
+                        let (rhs, raw_shift) =
+                            if name == sym::rotate_left || name == sym::rotate_right {
+                                // rotate = funnel shift with first two args the same
+                                (lhs, args[1].immediate())
+                            } else {
+                                (args[1].immediate(), args[2].immediate())
+                            };
                         let llvm_name = format!("llvm.fsh{}", if is_left { 'l' } else { 'r' });
 
                         // llvm expects shift to be the same type as the values, but rust
                         // always uses `u32`.
-                        let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);
+                        let raw_shift = self.intcast(raw_shift, self.val_ty(lhs), false);
 
-                        self.call_intrinsic(llvm_name, &[llty], &[val, val, raw_shift])
+                        self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs, raw_shift])
                     }
                     sym::saturating_add | sym::saturating_sub => {
                         let is_add = name == sym::saturating_add;
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 628cb34fd9e..6fb23d09843 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -211,11 +211,8 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     ) -> CompiledModule {
         back::write::codegen(cgcx, module, config)
     }
-    fn prepare_thin(
-        module: ModuleCodegen<Self::Module>,
-        emit_summary: bool,
-    ) -> (String, Self::ThinBuffer) {
-        back::lto::prepare_thin(module, emit_summary)
+    fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
+        back::lto::prepare_thin(module)
     }
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
         (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index b66fc157b3c..0679f55ab7f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2602,7 +2602,6 @@ unsafe extern "C" {
     pub(crate) fn LLVMRustThinLTOBufferCreate(
         M: &Module,
         is_thin: bool,
-        emit_summary: bool,
     ) -> &'static mut ThinLTOBuffer;
     pub(crate) fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
     pub(crate) fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 4e7096da502..53218340414 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -7,6 +7,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
+use rustc_span::{DUMMY_SP, Span};
 use tracing::debug;
 
 use crate::common::*;
@@ -149,7 +150,11 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
     }
 
     pub(crate) fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) {
-        let layout = self.layout_of(ty);
+        self.spanned_size_and_align_of(ty, DUMMY_SP)
+    }
+
+    pub(crate) fn spanned_size_and_align_of(&self, ty: Ty<'tcx>, span: Span) -> (Size, Align) {
+        let layout = self.spanned_layout_of(ty, span);
         (layout.size, layout.align.abi)
     }
 }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 44b9941691a..dd688b8b345 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -40,15 +40,15 @@ codegen_ssa_dynamic_linking_with_lto =
     .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
 
 codegen_ssa_error_calling_dlltool =
-    Error calling dlltool '{$dlltool_path}': {$error}
+    error calling dlltool '{$dlltool_path}': {$error}
 
 codegen_ssa_error_creating_import_library =
-    Error creating import library for {$lib_name}: {$error}
+    error creating import library for {$lib_name}: {$error}
 
 codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
 
 codegen_ssa_error_writing_def_file =
-    Error writing .DEF file: {$error}
+    error writing .DEF file: {$error}
 
 codegen_ssa_expected_name_value_pair = expected name value pair
 
@@ -264,9 +264,9 @@ codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at c
 
 codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
 
-codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
+codegen_ssa_static_library_native_artifacts = link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
 
-codegen_ssa_static_library_native_artifacts_to_file = Native artifacts to link against have been written to {$path}. The order and any duplication can be significant on some platforms.
+codegen_ssa_static_library_native_artifacts_to_file = native artifacts to link against have been written to {$path}. The order and any duplication can be significant on some platforms.
 
 codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status}
     .note = {$output}
@@ -364,13 +364,13 @@ codegen_ssa_unable_to_run = unable to run `{$util}`: {$error}
 
 codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
 
-codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error}
+codegen_ssa_unable_to_write_debugger_visualizer = unable to write debugger visualizer file `{$path}`: {$error}
 
 codegen_ssa_unexpected_parameter_name = unexpected parameter name
     .label = expected `{$prefix_nops}` or `{$entry_nops}`
 
 codegen_ssa_unknown_archive_kind =
-    Don't know how to build archive of type: {$kind}
+    don't know how to build archive of type: {$kind}
 
 codegen_ssa_unknown_ctarget_feature =
     unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 19c919c0e4e..48b01ea2df1 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -58,6 +58,7 @@ use super::linker::{self, Linker};
 use super::metadata::{MetadataPosition, create_wrapper_file};
 use super::rpath::{self, RPathConfig};
 use super::{apple, versioned_llvm_target};
+use crate::base::needs_allocator_shim_for_linking;
 use crate::{
     CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file,
 };
@@ -2080,9 +2081,17 @@ fn add_local_crate_regular_objects(cmd: &mut dyn Linker, codegen_results: &Codeg
 }
 
 /// Add object files for allocator code linked once for the whole crate tree.
-fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &CodegenResults) {
-    if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()) {
-        cmd.add_object(obj);
+fn add_local_crate_allocator_objects(
+    cmd: &mut dyn Linker,
+    codegen_results: &CodegenResults,
+    crate_type: CrateType,
+) {
+    if needs_allocator_shim_for_linking(&codegen_results.crate_info.dependency_formats, crate_type)
+    {
+        if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref())
+        {
+            cmd.add_object(obj);
+        }
     }
 }
 
@@ -2281,7 +2290,7 @@ fn linker_with_args(
         codegen_results,
         metadata,
     );
-    add_local_crate_allocator_objects(cmd, codegen_results);
+    add_local_crate_allocator_objects(cmd, codegen_results, crate_type);
 
     // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
     // at the point at which they are specified on the command line.
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index df1e91b12f9..a2efd420a32 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -11,8 +11,9 @@ use rustc_metadata::{
 };
 use rustc_middle::bug;
 use rustc_middle::middle::dependency_format::Linkage;
-use rustc_middle::middle::exported_symbols;
-use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
+use rustc_middle::middle::exported_symbols::{
+    self, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
+};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
@@ -22,6 +23,8 @@ use tracing::{debug, warn};
 
 use super::command::Command;
 use super::symbol_export;
+use crate::back::symbol_export::allocator_shim_symbols;
+use crate::base::needs_allocator_shim_for_linking;
 use crate::errors;
 
 #[cfg(test)]
@@ -1827,7 +1830,7 @@ fn exported_symbols_for_non_proc_macro(
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
     for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
         // Do not export mangled symbols from cdylibs and don't attempt to export compiler-builtins
-        // from any cdylib. The latter doesn't work anyway as we use hidden visibility for
+        // from any dylib. The latter doesn't work anyway as we use hidden visibility for
         // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning.
         if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
             symbols.push((
@@ -1838,6 +1841,14 @@ fn exported_symbols_for_non_proc_macro(
         }
     });
 
+    // Mark allocator shim symbols as exported only if they were generated.
+    if export_threshold == SymbolExportLevel::Rust
+        && needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type)
+        && tcx.allocator_kind(()).is_some()
+    {
+        symbols.extend(allocator_shim_symbols(tcx));
+    }
+
     symbols
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs
index c95038375a1..e6df6a2469f 100644
--- a/compiler/rustc_codegen_ssa/src/back/lto.rs
+++ b/compiler/rustc_codegen_ssa/src/back/lto.rs
@@ -8,8 +8,9 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{CrateType, Lto};
 use tracing::info;
 
-use crate::back::symbol_export::{self, symbol_name_for_instance_in_crate};
+use crate::back::symbol_export::{self, allocator_shim_symbols, symbol_name_for_instance_in_crate};
 use crate::back::write::CodegenContext;
+use crate::base::allocator_kind_for_codegen;
 use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro};
 use crate::traits::*;
 
@@ -115,6 +116,11 @@ pub(super) fn exported_symbols_for_lto(
         }
     }
 
+    // Mark allocator shim symbols as exported only if they were generated.
+    if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() {
+        symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name));
+    }
+
     symbols_below_threshold
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index d8a1480e911..b49e67217fb 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -18,7 +18,7 @@ use rustc_symbol_mangling::mangle_internal_symbol;
 use rustc_target::spec::TlsModel;
 use tracing::debug;
 
-use crate::base::allocator_kind_for_codegen;
+use crate::back::symbol_export;
 
 fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
     crates_export_threshold(tcx.crate_types())
@@ -217,31 +217,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>(
         ));
     }
 
-    // Mark allocator shim symbols as exported only if they were generated.
-    if allocator_kind_for_codegen(tcx).is_some() {
-        for symbol_name in ALLOCATOR_METHODS
-            .iter()
-            .map(|method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
-            .chain([
-                mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
-                mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
-                mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
-            ])
-        {
-            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
-
-            symbols.push((
-                exported_symbol,
-                SymbolExportInfo {
-                    level: SymbolExportLevel::Rust,
-                    kind: SymbolExportKind::Text,
-                    used: false,
-                    rustc_std_internal_symbol: true,
-                },
-            ));
-        }
-    }
-
     // Sort so we get a stable incr. comp. hash.
     symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));
 
@@ -516,6 +491,31 @@ pub(crate) fn provide(providers: &mut Providers) {
         upstream_monomorphizations_for_provider;
 }
 
+pub(crate) fn allocator_shim_symbols(
+    tcx: TyCtxt<'_>,
+) -> impl Iterator<Item = (String, SymbolExportKind)> {
+    ALLOCATOR_METHODS
+        .iter()
+        .map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
+        .chain([
+            mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
+            mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
+            mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
+        ])
+        .map(move |symbol_name| {
+            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
+
+            (
+                symbol_export::exporting_symbol_name_for_instance_in_crate(
+                    tcx,
+                    exported_symbol,
+                    LOCAL_CRATE,
+                ),
+                SymbolExportKind::Text,
+            )
+        })
+}
+
 fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel {
     // We export anything that's not mangled at the "C" layer as it probably has
     // to do with ABI concerns. We do not, however, apply such treatment to
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 8586615f7c7..cbaf67d7345 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -333,8 +333,8 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub crate_types: Vec<CrateType>,
     pub output_filenames: Arc<OutputFilenames>,
     pub invocation_temp: Option<String>,
-    pub regular_module_config: Arc<ModuleConfig>,
-    pub allocator_module_config: Arc<ModuleConfig>,
+    pub module_config: Arc<ModuleConfig>,
+    pub allocator_config: Arc<ModuleConfig>,
     pub tm_factory: TargetMachineFactoryFn<B>,
     pub msvc_imps_needed: bool,
     pub is_pe_coff: bool,
@@ -372,13 +372,6 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
     pub fn create_dcx(&self) -> DiagCtxt {
         DiagCtxt::new(Box::new(self.diag_emitter.clone()))
     }
-
-    pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
-        match kind {
-            ModuleKind::Regular => &self.regular_module_config,
-            ModuleKind::Allocator => &self.allocator_module_config,
-        }
-    }
 }
 
 fn generate_thin_lto_work<B: ExtraBackendMethods>(
@@ -442,6 +435,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
     backend: B,
     tcx: TyCtxt<'_>,
     target_cpu: String,
+    allocator_module: Option<ModuleCodegen<B::Module>>,
 ) -> OngoingCodegen<B> {
     let (coordinator_send, coordinator_receive) = channel();
 
@@ -465,6 +459,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
         coordinator_receive,
         Arc::new(regular_config),
         Arc::new(allocator_config),
+        allocator_module,
         coordinator_send.clone(),
     );
 
@@ -720,15 +715,6 @@ pub(crate) enum WorkItem<B: WriteBackendMethods> {
 }
 
 impl<B: WriteBackendMethods> WorkItem<B> {
-    fn module_kind(&self) -> ModuleKind {
-        match *self {
-            WorkItem::Optimize(ref m) => m.kind,
-            WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto { .. } | WorkItem::ThinLto(_) => {
-                ModuleKind::Regular
-            }
-        }
-    }
-
     /// Generate a short description of this work item suitable for use as a thread name.
     fn short_description(&self) -> String {
         // `pthread_setname()` on *nix ignores anything beyond the first 15
@@ -817,7 +803,7 @@ pub(crate) fn compute_per_cgu_lto_type(
     let linker_does_lto = opts.cg.linker_plugin_lto.enabled();
 
     // When we're automatically doing ThinLTO for multi-codegen-unit
-    // builds we don't actually want to LTO the allocator modules if
+    // builds we don't actually want to LTO the allocator module if
     // it shows up. This is due to various linker shenanigans that
     // we'll encounter later.
     let is_allocator = module_kind == ModuleKind::Allocator;
@@ -843,11 +829,17 @@ pub(crate) fn compute_per_cgu_lto_type(
 fn execute_optimize_work_item<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
     mut module: ModuleCodegen<B::Module>,
-    module_config: &ModuleConfig,
 ) -> WorkItemResult<B> {
+    let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*module.name);
+
     let dcx = cgcx.create_dcx();
     let dcx = dcx.handle();
 
+    let module_config = match module.kind {
+        ModuleKind::Regular => &cgcx.module_config,
+        ModuleKind::Allocator => &cgcx.allocator_config,
+    };
+
     B::optimize(cgcx, dcx, &mut module, module_config);
 
     // After we've done the initial round of optimizations we need to
@@ -859,7 +851,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
 
     // If we're doing some form of incremental LTO then we need to be sure to
     // save our module to disk first.
-    let bitcode = if cgcx.config(module.kind).emit_pre_lto_bc {
+    let bitcode = if module_config.emit_pre_lto_bc {
         let filename = pre_lto_bitcode_filename(&module.name);
         cgcx.incr_comp_session_dir.as_ref().map(|path| path.join(&filename))
     } else {
@@ -872,7 +864,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
             WorkItemResult::Finished(module)
         }
         ComputedLtoType::Thin => {
-            let (name, thin_buffer) = B::prepare_thin(module, false);
+            let (name, thin_buffer) = B::prepare_thin(module);
             if let Some(path) = bitcode {
                 fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| {
                     panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
@@ -899,8 +891,11 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
 fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
     module: CachedModuleCodegen,
-    module_config: &ModuleConfig,
 ) -> WorkItemResult<B> {
+    let _timer = cgcx
+        .prof
+        .generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*module.name);
+
     let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
 
     let mut links_from_incr_cache = Vec::new();
@@ -959,6 +954,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
         }
     };
 
+    let module_config = &cgcx.module_config;
     let should_emit_obj = module_config.emit_obj != EmitObj::None;
     let assembly = load_from_incr_cache(module_config.emit_asm, OutputType::Assembly);
     let llvm_ir = load_from_incr_cache(module_config.emit_ir, OutputType::LlvmAssembly);
@@ -970,8 +966,8 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
 
     WorkItemResult::Finished(CompiledModule {
         links_from_incr_cache,
-        name: module.name,
         kind: ModuleKind::Regular,
+        name: module.name,
         object,
         dwarf_object,
         bytecode,
@@ -986,8 +982,9 @@ fn execute_fat_lto_work_item<B: ExtraBackendMethods>(
     each_linked_rlib_for_lto: &[PathBuf],
     mut needs_fat_lto: Vec<FatLtoInput<B>>,
     import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
-    module_config: &ModuleConfig,
 ) -> WorkItemResult<B> {
+    let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", "everything");
+
     for (module, wp) in import_only_modules {
         needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module })
     }
@@ -998,17 +995,18 @@ fn execute_fat_lto_work_item<B: ExtraBackendMethods>(
         each_linked_rlib_for_lto,
         needs_fat_lto,
     );
-    let module = B::codegen(cgcx, module, module_config);
+    let module = B::codegen(cgcx, module, &cgcx.module_config);
     WorkItemResult::Finished(module)
 }
 
 fn execute_thin_lto_work_item<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
     module: lto::ThinModule<B>,
-    module_config: &ModuleConfig,
 ) -> WorkItemResult<B> {
+    let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", module.name());
+
     let module = B::optimize_thin(cgcx, module);
-    let module = B::codegen(cgcx, module, module_config);
+    let module = B::codegen(cgcx, module, &cgcx.module_config);
     WorkItemResult::Finished(module)
 }
 
@@ -1093,6 +1091,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     coordinator_receive: Receiver<Message<B>>,
     regular_config: Arc<ModuleConfig>,
     allocator_config: Arc<ModuleConfig>,
+    allocator_module: Option<ModuleCodegen<B::Module>>,
     tx_to_llvm_workers: Sender<Message<B>>,
 ) -> thread::JoinHandle<Result<CompiledModules, ()>> {
     let coordinator_send = tx_to_llvm_workers;
@@ -1157,8 +1156,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
         expanded_args: tcx.sess.expanded_args.clone(),
         diag_emitter: shared_emitter.clone(),
         output_filenames: Arc::clone(tcx.output_filenames(())),
-        regular_module_config: regular_config,
-        allocator_module_config: allocator_config,
+        module_config: regular_config,
+        allocator_config,
         tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features),
         msvc_imps_needed: msvc_imps_needed(tcx),
         is_pe_coff: tcx.sess.target.is_like_windows,
@@ -1312,7 +1311,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         // This is where we collect codegen units that have gone all the way
         // through codegen and LLVM.
         let mut compiled_modules = vec![];
-        let mut compiled_allocator_module = None;
         let mut needs_fat_lto = Vec::new();
         let mut needs_thin_lto = Vec::new();
         let mut lto_import_only_modules = Vec::new();
@@ -1353,6 +1351,17 @@ fn start_executing_work<B: ExtraBackendMethods>(
 
         let mut llvm_start_time: Option<VerboseTimingGuard<'_>> = None;
 
+        let compiled_allocator_module = allocator_module.and_then(|allocator_module| {
+            match execute_optimize_work_item(&cgcx, allocator_module) {
+                WorkItemResult::Finished(compiled_module) => return Some(compiled_module),
+                WorkItemResult::NeedsFatLto(fat_lto_input) => needs_fat_lto.push(fat_lto_input),
+                WorkItemResult::NeedsThinLto(name, thin_buffer) => {
+                    needs_thin_lto.push((name, thin_buffer))
+                }
+            }
+            None
+        });
+
         // Run the message loop while there's still anything that needs message
         // processing. Note that as soon as codegen is aborted we simply want to
         // wait for all existing work to finish, so many of the conditions here
@@ -1586,15 +1595,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
 
                     match result {
                         Ok(WorkItemResult::Finished(compiled_module)) => {
-                            match compiled_module.kind {
-                                ModuleKind::Regular => {
-                                    compiled_modules.push(compiled_module);
-                                }
-                                ModuleKind::Allocator => {
-                                    assert!(compiled_allocator_module.is_none());
-                                    compiled_allocator_module = Some(compiled_module);
-                                }
-                            }
+                            compiled_modules.push(compiled_module);
                         }
                         Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => {
                             assert!(!started_lto);
@@ -1722,46 +1723,22 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
     let cgcx = cgcx.clone();
 
     B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
-        let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
-            let module_config = cgcx.config(work.module_kind());
-
-            match work {
-                WorkItem::Optimize(m) => {
-                    let _timer =
-                        cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name);
-                    execute_optimize_work_item(&cgcx, m, module_config)
-                }
-                WorkItem::CopyPostLtoArtifacts(m) => {
-                    let _timer = cgcx.prof.generic_activity_with_arg(
-                        "codegen_copy_artifacts_from_incr_cache",
-                        &*m.name,
-                    );
-                    execute_copy_from_cache_work_item(&cgcx, m, module_config)
-                }
-                WorkItem::FatLto {
-                    exported_symbols_for_lto,
-                    each_linked_rlib_for_lto,
-                    needs_fat_lto,
-                    import_only_modules,
-                } => {
-                    let _timer = cgcx
-                        .prof
-                        .generic_activity_with_arg("codegen_module_perform_lto", "everything");
-                    execute_fat_lto_work_item(
-                        &cgcx,
-                        &exported_symbols_for_lto,
-                        &each_linked_rlib_for_lto,
-                        needs_fat_lto,
-                        import_only_modules,
-                        module_config,
-                    )
-                }
-                WorkItem::ThinLto(m) => {
-                    let _timer =
-                        cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name());
-                    execute_thin_lto_work_item(&cgcx, m, module_config)
-                }
-            }
+        let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work {
+            WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, m),
+            WorkItem::CopyPostLtoArtifacts(m) => execute_copy_from_cache_work_item(&cgcx, m),
+            WorkItem::FatLto {
+                exported_symbols_for_lto,
+                each_linked_rlib_for_lto,
+                needs_fat_lto,
+                import_only_modules,
+            } => execute_fat_lto_work_item(
+                &cgcx,
+                &exported_symbols_for_lto,
+                &each_linked_rlib_for_lto,
+                needs_fat_lto,
+                import_only_modules,
+            ),
+            WorkItem::ThinLto(m) => execute_thin_lto_work_item(&cgcx, m),
         }));
 
         let msg = match result {
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 8abaf201aba..45b028aa8ef 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -17,6 +17,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemId, Target};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
 use rustc_middle::middle::lang_items;
 use rustc_middle::mir::BinOp;
@@ -630,14 +631,30 @@ pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
     // If the crate doesn't have an `allocator_kind` set then there's definitely
     // no shim to generate. Otherwise we also check our dependency graph for all
     // our output crate types. If anything there looks like its a `Dynamic`
-    // linkage, then it's already got an allocator shim and we'll be using that
-    // one instead. If nothing exists then it's our job to generate the
-    // allocator!
-    let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
+    // linkage for all crate types we may link as, then it's already got an
+    // allocator shim and we'll be using that one instead. If nothing exists
+    // then it's our job to generate the allocator! If crate types disagree
+    // about whether an allocator shim is necessary or not, we generate one
+    // and let needs_allocator_shim_for_linking decide at link time whether or
+    // not to use it for any particular linker invocation.
+    let all_crate_types_any_dynamic_crate = tcx.dependency_formats(()).iter().all(|(_, list)| {
         use rustc_middle::middle::dependency_format::Linkage;
         list.iter().any(|&linkage| linkage == Linkage::Dynamic)
     });
-    if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
+    if all_crate_types_any_dynamic_crate { None } else { tcx.allocator_kind(()) }
+}
+
+/// Decide if this particular crate type needs an allocator shim linked in.
+/// This may return true even when allocator_kind_for_codegen returns false. In
+/// this case no allocator shim shall be linked.
+pub(crate) fn needs_allocator_shim_for_linking(
+    dependency_formats: &Dependencies,
+    crate_type: CrateType,
+) -> bool {
+    use rustc_middle::middle::dependency_format::Linkage;
+    let any_dynamic_crate =
+        dependency_formats[&crate_type].iter().any(|&linkage| linkage == Linkage::Dynamic);
+    !any_dynamic_crate
 }
 
 pub fn codegen_crate<B: ExtraBackendMethods>(
@@ -647,7 +664,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 ) -> OngoingCodegen<B> {
     // Skip crate items and just output metadata in -Z no-codegen mode.
     if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
-        let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu);
+        let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, None);
 
         ongoing_codegen.codegen_finished(tcx);
 
@@ -678,7 +695,27 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         }
     }
 
-    let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu);
+    // Codegen an allocator shim, if necessary.
+    let allocator_module = if let Some(kind) = allocator_kind_for_codegen(tcx) {
+        let llmod_id =
+            cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
+
+        tcx.sess.time("write_allocator_module", || {
+            let module = backend.codegen_allocator(
+                tcx,
+                &llmod_id,
+                kind,
+                // If allocator_kind is Some then alloc_error_handler_kind must
+                // also be Some.
+                tcx.alloc_error_handler_kind(()).unwrap(),
+            );
+            Some(ModuleCodegen::new_allocator(llmod_id, module))
+        })
+    } else {
+        None
+    };
+
+    let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, allocator_module);
 
     // For better throughput during parallel processing by LLVM, we used to sort
     // CGUs largest to smallest. This would lead to better thread utilization
@@ -795,35 +832,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         }
     }
 
-    // Codegen an allocator shim, if necessary.
-    // Do this last to ensure the LLVM_passes timer doesn't start while no CGUs have been codegened
-    // yet for the backend to optimize.
-    if let Some(kind) = allocator_kind_for_codegen(tcx) {
-        let llmod_id =
-            cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
-        let module_llvm = tcx.sess.time("write_allocator_module", || {
-            backend.codegen_allocator(
-                tcx,
-                &llmod_id,
-                kind,
-                // If allocator_kind is Some then alloc_error_handler_kind must
-                // also be Some.
-                tcx.alloc_error_handler_kind(()).unwrap(),
-            )
-        });
-
-        ongoing_codegen.wait_for_signal_to_codegen_item();
-        ongoing_codegen.check_for_errors(tcx.sess);
-
-        // These modules are generally cheap and won't throw off scheduling.
-        let cost = 0;
-        submit_codegened_module_to_llvm(
-            &ongoing_codegen.coordinator,
-            ModuleCodegen::new_allocator(llmod_id, module_llvm),
-            cost,
-        );
-    }
-
     ongoing_codegen.codegen_finished(tcx);
 
     // Since the main thread is sometimes blocked during codegen, we keep track
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 961bb788149..008340e614d 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -428,9 +428,16 @@ fn check_result(
     // llvm/llvm-project#70563).
     if !codegen_fn_attrs.target_features.is_empty()
         && matches!(codegen_fn_attrs.inline, InlineAttr::Always)
+        && !tcx.features().target_feature_inline_always()
         && let Some(span) = interesting_spans.inline
     {
-        tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
+        feature_err(
+            tcx.sess,
+            sym::target_feature_inline_always,
+            span,
+            "cannot use `#[inline(always)]` with `#[target_feature]`",
+        )
+        .emit();
     }
 
     // warn that inline has no effect when no_sanitize is present
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index fe0500a5d4c..baba8f9ca3e 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -119,7 +119,7 @@ impl<M> ModuleCodegen<M> {
         });
 
         CompiledModule {
-            name: self.name.clone(),
+            name: self.name,
             kind: self.kind,
             object,
             dwarf_object,
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 8a67b8d6e5f..f6f2e3f2a3a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -1,3 +1,4 @@
+use itertools::Itertools as _;
 use rustc_abi::{self as abi, FIRST_VARIANT};
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
@@ -111,14 +112,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     let size = bx.const_usize(dest.layout.size.bytes());
 
                     // Use llvm.memset.p0i8.* to initialize all same byte arrays
-                    if let Some(int) = bx.cx().const_to_opt_u128(v, false) {
-                        let bytes = &int.to_le_bytes()[..cg_elem.layout.size.bytes_usize()];
-                        let first = bytes[0];
-                        if bytes[1..].iter().all(|&b| b == first) {
-                            let fill = bx.cx().const_u8(first);
-                            bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
-                            return true;
-                        }
+                    if let Some(int) = bx.cx().const_to_opt_u128(v, false)
+                        && let bytes = &int.to_le_bytes()[..cg_elem.layout.size.bytes_usize()]
+                        && let Ok(&byte) = bytes.iter().all_equal_value()
+                    {
+                        let fill = bx.cx().const_u8(byte);
+                        bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
+                        return true;
                     }
 
                     // Use llvm.memset.p0i8.* to initialize byte arrays
@@ -130,13 +130,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     false
                 };
 
-                match cg_elem.val {
-                    OperandValue::Immediate(v) => {
-                        if try_init_all_same(bx, v) {
-                            return;
-                        }
-                    }
-                    _ => (),
+                if let OperandValue::Immediate(v) = cg_elem.val
+                    && try_init_all_same(bx, v)
+                {
+                    return;
                 }
 
                 let count = self
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index cc7c4e46d7b..1ac1d7ef2e2 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -50,16 +50,12 @@ pub trait WriteBackendMethods: Clone + 'static {
         module: ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> CompiledModule;
-    fn prepare_thin(
-        module: ModuleCodegen<Self::Module>,
-        want_summary: bool,
-    ) -> (String, Self::ThinBuffer);
+    fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer);
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
 }
 
 pub trait ThinBufferMethods: Send + Sync {
     fn data(&self) -> &[u8];
-    fn thin_link_data(&self) -> &[u8];
 }
 
 pub trait ModuleBufferMethods: Send + Sync {
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 60518dafbf2..700d7c26752 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -457,7 +457,7 @@ const_eval_validation_failure =
     it is undefined behavior to use this value
 
 const_eval_validation_failure_note =
-    The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+    the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 const_eval_validation_front_matter_invalid_value = constructing invalid value
 const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path}
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 9681d89ce35..91ed71ac3e5 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -4,6 +4,7 @@ use either::{Left, Right};
 use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_errors::DiagCtxtHandle;
 use rustc_hir::def_id::DefId;
+use rustc_hir::limit::Limit;
 use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
@@ -12,7 +13,6 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
 use rustc_middle::{mir, span_bug};
-use rustc_session::Limit;
 use rustc_span::Span;
 use rustc_target::callconv::FnAbi;
 use tracing::{debug, trace};
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 2ae6655901b..5bcf96abd8c 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -168,10 +168,11 @@ impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
         // Bound regions are always printed (as `'_`), which gives some idea that they are special,
         // even though the `for` is omitted by the pretty printer.
         // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)".
+        let kind = region.kind();
         match region.kind() {
-            ty::ReErased | ty::ReEarlyParam(_) => false,
+            ty::ReErased | ty::ReEarlyParam(_) | ty::ReStatic => false,
             ty::ReBound(..) => true,
-            _ => unreachable!(),
+            _ => panic!("type_name unhandled region: {kind:?}"),
         }
     }
 
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index 2c6a0291ac2..b62cdc35f51 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -14,7 +14,7 @@ driver_impl_ice_version = rustc {$version} running on {$triple}
 
 driver_impl_rlink_corrupt_file = corrupt metadata encountered in `{$file}`
 
-driver_impl_rlink_empty_version_number = The input does not contain version number
+driver_impl_rlink_empty_version_number = the input does not contain version number
 
 driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
 
@@ -24,6 +24,6 @@ driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc ver
 
 driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
 
-driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
+driver_impl_rlink_wrong_file_type = the input does not look like a .rlink file
 
 driver_impl_unstable_feature_usage = cannot dump feature usage metrics: {$error}
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 96a4ed3218f..ae23ef1e255 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -945,11 +945,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
             None,
             "Span must not be empty and have no suggestion",
         );
-        debug_assert_eq!(
-            parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
-            None,
-            "suggestion must not have overlapping parts",
-        );
 
         self.push_suggestion(CodeSuggestion {
             substitutions: vec![Substitution { parts }],
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index b94370e8e9b..93b1e6b7615 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -2354,7 +2354,6 @@ impl HumanEmitter {
                         .sum();
                     let underline_start = (span_start_pos + start) as isize + offset;
                     let underline_end = (span_start_pos + start + sub_len) as isize + offset;
-                    assert!(underline_start >= 0 && underline_end >= 0);
                     let padding: usize = max_line_num_len + 3;
                     for p in underline_start..underline_end {
                         if let DisplaySuggestion::Underline = show_code_change
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 71fc54f0d33..8869799ce90 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -381,6 +381,17 @@ impl CodeSuggestion {
                 // Assumption: all spans are in the same file, and all spans
                 // are disjoint. Sort in ascending order.
                 substitution.parts.sort_by_key(|part| part.span.lo());
+                // Verify the assumption that all spans are disjoint
+                assert_eq!(
+                    substitution.parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
+                    None,
+                    "all spans must be disjoint",
+                );
+
+                // Account for cases where we are suggesting the same code that's already
+                // there. This shouldn't happen often, but in some cases for multipart
+                // suggestions it's much easier to handle it here than in the origin.
+                substitution.parts.retain(|p| is_different(sm, &p.snippet, p.span));
 
                 // Find the bounding span.
                 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
@@ -470,16 +481,12 @@ impl CodeSuggestion {
                             _ => 1,
                         })
                         .sum();
-                    if !is_different(sm, &part.snippet, part.span) {
-                        // Account for cases where we are suggesting the same code that's already
-                        // there. This shouldn't happen often, but in some cases for multipart
-                        // suggestions it's much easier to handle it here than in the origin.
-                    } else {
-                        line_highlight.push(SubstitutionHighlight {
-                            start: (cur_lo.col.0 as isize + acc) as usize,
-                            end: (cur_lo.col.0 as isize + acc + len) as usize,
-                        });
-                    }
+
+                    line_highlight.push(SubstitutionHighlight {
+                        start: (cur_lo.col.0 as isize + acc) as usize,
+                        end: (cur_lo.col.0 as isize + acc + len) as usize,
+                    });
+
                     buf.push_str(&part.snippet);
                     let cur_hi = sm.lookup_char_pos(part.span.hi());
                     // Account for the difference between the width of the current code and the
@@ -1160,7 +1167,7 @@ impl<'a> DiagCtxtHandle<'a> {
         // - It's only produce with JSON output.
         // - It's not emitted the usual way, via `emit_diagnostic`.
         // - The `$message_type` field is "unused_externs" rather than the usual
-        //   "diagnosic".
+        //   "diagnostic".
         //
         // We count it as a lint error because it has a lint level. The value
         // of `loud` (which comes from "unused-externs" or
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 8ff21509f4a..88f88f30a8c 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -18,13 +18,14 @@ use rustc_feature::Features;
 use rustc_hir as hir;
 use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation};
 use rustc_hir::def::MacroKinds;
+use rustc_hir::limit::Limit;
 use rustc_hir::{Stability, find_attr};
 use rustc_lint_defs::RegisteredTools;
 use rustc_parse::MACRO_ARGUMENTS;
 use rustc_parse::parser::{ForceCollect, Parser};
+use rustc_session::Session;
 use rustc_session::config::CollapseMacroDebuginfo;
 use rustc_session::parse::ParseSess;
-use rustc_session::{Limit, Session};
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index ba9d76970f0..6eb5cd65846 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -2,8 +2,8 @@ use std::borrow::Cow;
 
 use rustc_ast::ast;
 use rustc_errors::codes::*;
+use rustc_hir::limit::Limit;
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_session::Limit;
 use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index dbb4a9de9e0..38e057d2776 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -19,14 +19,15 @@ use rustc_errors::PResult;
 use rustc_feature::Features;
 use rustc_hir::Target;
 use rustc_hir::def::MacroKinds;
+use rustc_hir::limit::Limit;
 use rustc_parse::parser::{
     AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
     token_descr,
 };
+use rustc_session::Session;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
 use rustc_session::parse::feature_err;
-use rustc_session::{Limit, Session};
 use rustc_span::hygiene::SyntaxContext;
 use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym};
 use smallvec::SmallVec;
@@ -2529,6 +2530,7 @@ impl ExpansionConfig<'_> {
         ExpansionConfig {
             crate_name,
             features,
+            // FIXME should this limit be configurable?
             recursion_limit: Limit::new(1024),
             trace_mac: false,
             should_test: false,
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 0324057e331..ab8e059b7b7 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -77,7 +77,7 @@ use std::rc::Rc;
 
 pub(crate) use NamedMatch::*;
 pub(crate) use ParseResult::*;
-use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
+use rustc_ast::token::{self, DocComment, NonterminalKind, Token, TokenKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_lint_defs::pluralize;
@@ -397,7 +397,23 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
     {
         ident1.name == ident2.name && is_raw1 == is_raw2
     } else {
-        t1.kind == t2.kind
+        // Note: we SHOULD NOT use `t1.kind == t2.kind` here, and we should instead compare the
+        // tokens using the special comparison logic below.
+        // It makes sure that variants containing `InvisibleOrigin` will
+        // never compare equal to one another.
+        //
+        // When we had AST-based nonterminals we couldn't compare them, and the
+        // old `Nonterminal` type had an `eq` that always returned false,
+        // resulting in this restriction:
+        // <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment>
+        // This comparison logic emulates that behaviour. We could consider lifting this
+        // restriction now but there are still cases involving invisible
+        // delimiters that make it harder than it first appears.
+        match (t1.kind, t2.kind) {
+            (TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_), _)
+            | (_, TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_)) => false,
+            (a, b) => a == b,
+        }
     }
 }
 
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 573e9aab055..4f35bf63a1a 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -642,6 +642,8 @@ declare_features! (
     (unstable, super_let, "1.88.0", Some(139076)),
     /// Allows subtrait items to shadow supertrait items.
     (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
+    /// Allows the use of target_feature when a function is marked inline(always).
+    (unstable, target_feature_inline_always, "CURRENT_RUSTC_VERSION", Some(145574)),
     /// Allows using `#[thread_local]` on `static` items.
     (unstable, thread_local, "1.0.0", Some(29594)),
     /// Allows defining `trait X = A + B;` alias items.
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index dd5565d6f90..b4c1b61b9b5 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -14,6 +14,7 @@ pub use rustc_target::spec::SanitizerSet;
 use thin_vec::ThinVec;
 
 use crate::attrs::pretty_printing::PrintAttribute;
+use crate::limit::Limit;
 use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
 
 #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
@@ -565,6 +566,9 @@ pub enum AttributeKind {
     /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html).
     MayDangle(Span),
 
+    /// Represents `#[move_size_limit]`
+    MoveSizeLimit { attr_span: Span, limit_span: Span, limit: Limit },
+
     /// Represents `#[must_use]`.
     MustUse {
         span: Span,
@@ -596,6 +600,9 @@ pub enum AttributeKind {
     /// Represents `#[path]`
     Path(Symbol, Span),
 
+    /// Represents `#[pattern_complexity_limit]`
+    PatternComplexityLimit { attr_span: Span, limit_span: Span, limit: Limit },
+
     /// Represents `#[pointee]`
     Pointee(Span),
 
@@ -611,6 +618,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
     PubTransparent(Span),
 
+    /// Represents [`#[recursion_limit]`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)
+    RecursionLimit { attr_span: Span, limit_span: Span, limit: Limit },
+
     /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
     Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
 
@@ -661,6 +671,9 @@ pub enum AttributeKind {
     /// Represents `#[type_const]`.
     TypeConst(Span),
 
+    /// Represents `#[type_length_limit]`
+    TypeLengthLimit { attr_span: Span, limit_span: Span, limit: Limit },
+
     /// Represents `#[rustc_unsafe_specialization_marker]`.
     UnsafeSpecializationMarker(Span),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 3810bb6d003..0e208be3497 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -61,6 +61,7 @@ impl AttributeKind {
             MacroUse { .. } => No,
             Marker(..) => No,
             MayDangle(..) => No,
+            MoveSizeLimit { .. } => No,
             MustUse { .. } => Yes,
             Naked(..) => No,
             NoImplicitPrelude(..) => No,
@@ -70,11 +71,13 @@ impl AttributeKind {
             ParenSugar(..) => No,
             PassByValue(..) => Yes,
             Path(..) => No,
+            PatternComplexityLimit { .. } => No,
             Pointee(..) => No,
             ProcMacro(..) => No,
             ProcMacroAttribute(..) => No,
             ProcMacroDerive { .. } => No,
             PubTransparent(..) => Yes,
+            RecursionLimit { .. } => No,
             Repr { .. } => No,
             RustcBuiltinMacro { .. } => Yes,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
@@ -89,6 +92,7 @@ impl AttributeKind {
             TargetFeature { .. } => No,
             TrackCaller(..) => Yes,
             TypeConst(..) => Yes,
+            TypeLengthLimit { .. } => No,
             UnsafeSpecializationMarker(..) => No,
             UnstableFeatureBound(..) => No,
             Used { .. } => No,
diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs
index e65de25b451..d13cd3fd1da 100644
--- a/compiler/rustc_hir/src/attrs/pretty_printing.rs
+++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs
@@ -9,6 +9,8 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
 use rustc_target::spec::SanitizerSet;
 use thin_vec::ThinVec;
 
+use crate::limit::Limit;
+
 /// This trait is used to print attributes in `rustc_hir_pretty`.
 ///
 /// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
@@ -146,7 +148,7 @@ macro_rules! print_tup {
 
 print_tup!(A B C D E F G H);
 print_skip!(Span, (), ErrorGuaranteed);
-print_disp!(u16, bool, NonZero<u32>);
+print_disp!(u16, bool, NonZero<u32>, Limit);
 print_debug!(
     Symbol,
     Ident,
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 78fc63753a2..eb630fc8018 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -25,6 +25,7 @@ mod hir;
 pub use rustc_hir_id::{self as hir_id, *};
 pub mod intravisit;
 pub mod lang_items;
+pub mod limit;
 pub mod lints;
 pub mod pat_util;
 mod stability;
diff --git a/compiler/rustc_hir/src/limit.rs b/compiler/rustc_hir/src/limit.rs
new file mode 100644
index 00000000000..7e6d23f51bd
--- /dev/null
+++ b/compiler/rustc_hir/src/limit.rs
@@ -0,0 +1,63 @@
+use std::fmt;
+use std::ops::{Div, Mul};
+
+use rustc_error_messages::{DiagArgValue, IntoDiagArg};
+use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+
+/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against
+/// limits are consistent throughout the compiler.
+#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable)]
+pub struct Limit(pub usize);
+
+impl Limit {
+    /// Create a new limit from a `usize`.
+    pub fn new(value: usize) -> Self {
+        Limit(value)
+    }
+
+    /// Create a new unlimited limit.
+    pub fn unlimited() -> Self {
+        Limit(usize::MAX)
+    }
+
+    /// Check that `value` is within the limit. Ensures that the same comparisons are used
+    /// throughout the compiler, as mismatches can cause ICEs, see #72540.
+    #[inline]
+    pub fn value_within_limit(&self, value: usize) -> bool {
+        value <= self.0
+    }
+}
+
+impl From<usize> for Limit {
+    fn from(value: usize) -> Self {
+        Self::new(value)
+    }
+}
+
+impl fmt::Display for Limit {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl Div<usize> for Limit {
+    type Output = Limit;
+
+    fn div(self, rhs: usize) -> Self::Output {
+        Limit::new(self.0 / rhs)
+    }
+}
+
+impl Mul<usize> for Limit {
+    type Output = Limit;
+
+    fn mul(self, rhs: usize) -> Self::Output {
+        Limit::new(self.0 * rhs)
+    }
+}
+
+impl IntoDiagArg for Limit {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self.to_string().into_diag_arg(&mut None)
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index e27e68d3662..e8237471e1b 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -1,7 +1,7 @@
+use rustc_hir::limit::Limit;
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_session::Limit;
 use rustc_span::def_id::{LOCAL_CRATE, LocalDefId};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::ObligationCtxt;
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index cfc6bc2f3a0..aa2d27ab809 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -449,6 +449,9 @@ pub(crate) fn check_intrinsic_type(
         }
         sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)),
         sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), tcx.types.u32], param(0)),
+        sym::unchecked_funnel_shl | sym::unchecked_funnel_shr => {
+            (1, 0, vec![param(0), param(0), tcx.types.u32], param(0))
+        }
         sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
             (1, 0, vec![param(0), param(0)], param(0))
         }
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index f5770b7312d..2ba7ed46f92 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -490,12 +490,8 @@ fn resolve_local<'tcx>(
             //
             // Iterate up to the enclosing destruction scope to find the same scope that will also
             // be used for the result of the block itself.
-            while let Some(s) = visitor.cx.var_parent {
-                let parent = visitor.scope_tree.parent_map.get(&s).cloned();
-                if let Some(Scope { data: ScopeData::Destruction, .. }) = parent {
-                    break;
-                }
-                visitor.cx.var_parent = parent;
+            if let Some(inner_scope) = visitor.cx.var_parent {
+                (visitor.cx.var_parent, _) = visitor.scope_tree.default_temporary_scope(inner_scope)
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 6565ad7cf53..3b6367219b7 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -6,6 +6,7 @@ use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
     MultiSpan,
 };
+use rustc_hir::limit::Limit;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{Ident, Span, Symbol};
@@ -557,7 +558,7 @@ pub(crate) struct AutoDerefReachedRecursionLimit<'a> {
     #[label]
     pub span: Span,
     pub ty: Ty<'a>,
-    pub suggested_limit: rustc_session::Limit,
+    pub suggested_limit: Limit,
     pub crate_name: Symbol,
 }
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index e66601631fc..b99f811db1a 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1897,7 +1897,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
                 }
             }
-        };
+        }
 
         // If this is due to an explicit `return`, suggest adding a return type.
         if let Some((fn_id, fn_decl)) = fcx.get_fn_decl(block_or_return_id)
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index a652e08905a..7adbee7ff28 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2585,12 +2585,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .filter(|item| item.is_fn() && !item.is_method())
                 .filter_map(|item| {
                     // Only assoc fns that return `Self`
-                    let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
-                    let ret_ty = fn_sig.output();
-                    let ret_ty = self.tcx.normalize_erasing_late_bound_regions(
-                        self.typing_env(self.param_env),
-                        ret_ty,
-                    );
+                    let fn_sig = self
+                        .tcx
+                        .fn_sig(item.def_id)
+                        .instantiate(self.tcx, self.fresh_args_for_item(span, item.def_id));
+                    let ret_ty = self.tcx.instantiate_bound_regions_with_erased(fn_sig.output());
                     if !self.can_eq(self.param_env, ret_ty, adt_ty) {
                         return None;
                     }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 5aec50c8b53..94b635c41b4 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1912,7 +1912,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::StmtKind::Expr(ref expr) => {
                 // Check with expected type of `()`.
                 self.check_expr_has_type_or_error(expr, self.tcx.types.unit, |err| {
-                    if expr.can_have_side_effects() {
+                    if self.is_next_stmt_expr_continuation(stmt.hir_id)
+                        && let hir::ExprKind::Match(..) | hir::ExprKind::If(..) = expr.kind
+                    {
+                        // We have something like `match () { _ => true } && true`. Suggest
+                        // wrapping in parentheses. We find the statement or expression
+                        // following the `match` (`&& true`) and see if it is something that
+                        // can reasonably be interpreted as a binop following an expression.
+                        err.multipart_suggestion(
+                            "parentheses are required to parse this as an expression",
+                            vec![
+                                (expr.span.shrink_to_lo(), "(".to_string()),
+                                (expr.span.shrink_to_hi(), ")".to_string()),
+                            ],
+                            Applicability::MachineApplicable,
+                        );
+                    } else if expr.can_have_side_effects() {
                         self.suggest_semicolon_at_end(expr.span, err);
                     }
                 });
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 74f27e85cba..7a060cafeab 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -21,7 +21,6 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
 use rustc_trait_selection::error_reporting::TypeErrCtxt;
-use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
 use rustc_trait_selection::traits::{
     self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
 };
@@ -188,14 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt
     pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
-        let mut sub_relations = SubRelations::default();
-        sub_relations.add_constraints(
-            self,
-            self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate),
-        );
         TypeErrCtxt {
             infcx: &self.infcx,
-            sub_relations: RefCell::new(sub_relations),
             typeck_results: Some(self.typeck_results.borrow()),
             fallback_has_occurred: self.fallback_has_occurred.get(),
             normalize_fn_sig: Box::new(|fn_sig| {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index aca3840712e..84ea2ec0f8a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 use core::cmp::min;
 use core::iter;
 
@@ -766,56 +767,121 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         needs_block: bool,
         parent_is_closure: bool,
     ) {
-        if expected.is_unit() {
-            // `BlockTailExpression` only relevant if the tail expr would be
-            // useful on its own.
-            match expression.kind {
-                ExprKind::Call(..)
-                | ExprKind::MethodCall(..)
-                | ExprKind::Loop(..)
-                | ExprKind::If(..)
-                | ExprKind::Match(..)
-                | ExprKind::Block(..)
-                    if expression.can_have_side_effects()
-                        // If the expression is from an external macro, then do not suggest
-                        // adding a semicolon, because there's nowhere to put it.
-                        // See issue #81943.
-                        && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
+        if !expected.is_unit() {
+            return;
+        }
+        // `BlockTailExpression` only relevant if the tail expr would be
+        // useful on its own.
+        match expression.kind {
+            ExprKind::Call(..)
+            | ExprKind::MethodCall(..)
+            | ExprKind::Loop(..)
+            | ExprKind::If(..)
+            | ExprKind::Match(..)
+            | ExprKind::Block(..)
+                if expression.can_have_side_effects()
+                    // If the expression is from an external macro, then do not suggest
+                    // adding a semicolon, because there's nowhere to put it.
+                    // See issue #81943.
+                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
+            {
+                if needs_block {
+                    err.multipart_suggestion(
+                        "consider using a semicolon here",
+                        vec![
+                            (expression.span.shrink_to_lo(), "{ ".to_owned()),
+                            (expression.span.shrink_to_hi(), "; }".to_owned()),
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+                } else if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id)
+                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id)
+                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id)
+                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind
+                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id)
+                    && let hir::StmtKind::Expr(_) = stmt.kind
+                    && self.is_next_stmt_expr_continuation(stmt.hir_id)
                 {
-                    if needs_block {
-                        err.multipart_suggestion(
-                            "consider using a semicolon here",
-                            vec![
-                                (expression.span.shrink_to_lo(), "{ ".to_owned()),
-                                (expression.span.shrink_to_hi(), "; }".to_owned()),
-                            ],
-                            Applicability::MachineApplicable,
-                        );
-                    } else {
-                        err.span_suggestion(
-                            expression.span.shrink_to_hi(),
-                            "consider using a semicolon here",
-                            ";",
-                            Applicability::MachineApplicable,
-                        );
-                    }
+                    err.multipart_suggestion(
+                        "parentheses are required to parse this as an expression",
+                        vec![
+                            (stmt.span.shrink_to_lo(), "(".to_string()),
+                            (stmt.span.shrink_to_hi(), ")".to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.span_suggestion(
+                        expression.span.shrink_to_hi(),
+                        "consider using a semicolon here",
+                        ";",
+                        Applicability::MachineApplicable,
+                    );
                 }
-                ExprKind::Path(..) | ExprKind::Lit(_)
-                    if parent_is_closure
-                        && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
+            }
+            ExprKind::Path(..) | ExprKind::Lit(_)
+                if parent_is_closure
+                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
+            {
+                err.span_suggestion_verbose(
+                    expression.span.shrink_to_lo(),
+                    "consider ignoring the value",
+                    "_ = ",
+                    Applicability::MachineApplicable,
+                );
+            }
+            _ => {
+                if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id)
+                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id)
+                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id)
+                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind
+                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id)
+                    && let hir::StmtKind::Expr(_) = stmt.kind
+                    && self.is_next_stmt_expr_continuation(stmt.hir_id)
                 {
-                    err.span_suggestion_verbose(
-                        expression.span.shrink_to_lo(),
-                        "consider ignoring the value",
-                        "_ = ",
+                    // The error is pointing at an arm of an if-expression, and we want to get the
+                    // `Span` of the whole if-expression for the suggestion. This only works for a
+                    // single level of nesting, which is fine.
+                    // We have something like `if true { false } else { true } && true`. Suggest
+                    // wrapping in parentheses. We find the statement or expression following the
+                    // `if` (`&& true`) and see if it is something that can reasonably be
+                    // interpreted as a binop following an expression.
+                    err.multipart_suggestion(
+                        "parentheses are required to parse this as an expression",
+                        vec![
+                            (stmt.span.shrink_to_lo(), "(".to_string()),
+                            (stmt.span.shrink_to_hi(), ")".to_string()),
+                        ],
                         Applicability::MachineApplicable,
                     );
                 }
-                _ => (),
             }
         }
     }
 
+    pub(crate) fn is_next_stmt_expr_continuation(&self, hir_id: HirId) -> bool {
+        if let hir::Node::Block(b) = self.tcx.parent_hir_node(hir_id)
+            && let mut stmts = b.stmts.iter().skip_while(|s| s.hir_id != hir_id)
+            && let Some(_) = stmts.next() // The statement the statement that was passed in
+            && let Some(next) = match (stmts.next(), b.expr) { // The following statement
+                (Some(next), _) => match next.kind {
+                    hir::StmtKind::Expr(next) | hir::StmtKind::Semi(next) => Some(next),
+                    _ => None,
+                },
+                (None, Some(next)) => Some(next),
+                _ => None,
+            }
+            && let hir::ExprKind::AddrOf(..) // prev_stmt && next
+                | hir::ExprKind::Unary(..) // prev_stmt * next
+                | hir::ExprKind::Err(_) = next.kind
+        // prev_stmt + next
+        {
+            true
+        } else {
+            false
+        }
+    }
+
     /// A possible error is to forget to add a return type that is needed:
     ///
     /// ```compile_fail,E0308
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index ab584eb7c90..52a8eff984b 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -403,15 +403,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // special handling for this "trivial case" is a good idea.
 
                 let infcx = &self.infcx;
-                let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) =
+                let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) =
                     infcx.instantiate_canonical(span, &query_input.canonical);
                 debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
                 MethodAutoderefStepsResult {
                     steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
-                        self_ty: self.make_query_response_ignoring_pending_obligations(
-                            canonical_inference_vars,
-                            self_ty,
-                        ),
+                        self_ty: self
+                            .make_query_response_ignoring_pending_obligations(var_values, self_ty),
                         autoderefs: 0,
                         from_unsafe_deref: false,
                         unsize: false,
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
index 0225c5c4f32..dda5253e7c5 100644
--- a/compiler/rustc_index/src/interval.rs
+++ b/compiler/rustc_index/src/interval.rs
@@ -140,6 +140,30 @@ impl<I: Idx> IntervalSet<I> {
         result
     }
 
+    /// Specialized version of `insert` when we know that the inserted point is *after* any
+    /// contained.
+    pub fn append(&mut self, point: I) {
+        let point = point.index() as u32;
+
+        if let Some((_, last_end)) = self.map.last_mut() {
+            assert!(*last_end <= point);
+            if point == *last_end {
+                // The point is already in the set.
+            } else if point == *last_end + 1 {
+                *last_end = point;
+            } else {
+                self.map.push((point, point));
+            }
+        } else {
+            self.map.push((point, point));
+        }
+
+        debug_assert!(
+            self.check_invariants(),
+            "wrong intervals after append {point:?} to {self:?}"
+        );
+    }
+
     pub fn contains(&self, needle: I) -> bool {
         let needle = needle.index() as u32;
         let Some(last) = self.map.partition_point(|r| r.0 <= needle).checked_sub(1) else {
@@ -176,6 +200,32 @@ impl<I: Idx> IntervalSet<I> {
         })
     }
 
+    pub fn disjoint(&self, other: &IntervalSet<I>) -> bool
+    where
+        I: Step,
+    {
+        let helper = move || {
+            let mut self_iter = self.iter_intervals();
+            let mut other_iter = other.iter_intervals();
+
+            let mut self_current = self_iter.next()?;
+            let mut other_current = other_iter.next()?;
+
+            loop {
+                if self_current.end <= other_current.start {
+                    self_current = self_iter.next()?;
+                    continue;
+                }
+                if other_current.end <= self_current.start {
+                    other_current = other_iter.next()?;
+                    continue;
+                }
+                return Some(false);
+            }
+        };
+        helper().unwrap_or(true)
+    }
+
     pub fn is_empty(&self) -> bool {
         self.map.is_empty()
     }
@@ -325,6 +375,10 @@ impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> {
         self.ensure_row(row).insert(point)
     }
 
+    pub fn append(&mut self, row: R, point: C) {
+        self.ensure_row(row).append(point)
+    }
+
     pub fn contains(&self, row: R, point: C) -> bool {
         self.row(row).is_some_and(|r| r.contains(point))
     }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 3ad14dc79d5..3c5e4a91c98 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -6,6 +6,7 @@
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sso::SsoHashMap;
 use rustc_index::Idx;
 use rustc_middle::bug;
 use rustc_middle::ty::{
@@ -17,7 +18,7 @@ use tracing::debug;
 
 use crate::infer::InferCtxt;
 use crate::infer::canonical::{
-    Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarKind, OriginalQueryValues,
+    Canonical, CanonicalQueryInput, CanonicalVarKind, OriginalQueryValues,
 };
 
 impl<'tcx> InferCtxt<'tcx> {
@@ -293,6 +294,13 @@ struct Canonicalizer<'cx, 'tcx> {
     // Note that indices is only used once `var_values` is big enough to be
     // heap-allocated.
     indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
+    /// Maps each `sub_unification_table_root_var` to the index of the first
+    /// variable which used it.
+    ///
+    /// This means in case two type variables have the same sub relations root,
+    /// we set the `sub_root` of the second variable to the position of the first.
+    /// Otherwise the `sub_root` of each type variable is just its own position.
+    sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
     canonicalize_mode: &'cx dyn CanonicalizeMode,
     needs_canonical_flags: TypeFlags,
 
@@ -361,10 +369,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                             // FIXME: perf problem described in #55921.
                             ui = ty::UniverseIndex::ROOT;
                         }
-                        self.canonicalize_ty_var(
-                            CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
-                            t,
-                        )
+                        let sub_root = self.get_or_insert_sub_root(vid);
+                        self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t)
                     }
                 }
             }
@@ -374,7 +380,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 if nt != t {
                     return self.fold_ty(nt);
                 } else {
-                    self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t)
+                    self.canonicalize_ty_var(CanonicalVarKind::Int, t)
                 }
             }
             ty::Infer(ty::FloatVar(vid)) => {
@@ -382,7 +388,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 if nt != t {
                     return self.fold_ty(nt);
                 } else {
-                    self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t)
+                    self.canonicalize_ty_var(CanonicalVarKind::Float, t)
                 }
             }
 
@@ -562,6 +568,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             variables: SmallVec::from_slice(base.variables),
             query_state,
             indices: FxHashMap::default(),
+            sub_root_lookup_table: Default::default(),
             binder_index: ty::INNERMOST,
         };
         if canonicalizer.query_state.var_values.spilled() {
@@ -660,6 +667,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         }
     }
 
+    fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
+        let root_vid = self.infcx.unwrap().sub_unification_table_root_var(vid);
+        let idx =
+            *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
+        ty::BoundVar::from(idx)
+    }
+
     /// Replaces the universe indexes used in `var_values` with their index in
     /// `query_state.universe_map`. This minimizes the maximum universe used in
     /// the canonicalized value.
@@ -679,11 +693,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         self.variables
             .iter()
             .map(|&kind| match kind {
-                CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+                CanonicalVarKind::Int | CanonicalVarKind::Float => {
                     return kind;
                 }
-                CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
+                CanonicalVarKind::Ty { ui, sub_root } => {
+                    CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root }
                 }
                 CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
                 CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 79a2aa54ef8..f99f228e19d 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -24,7 +24,7 @@
 pub use instantiate::CanonicalExt;
 use rustc_index::IndexVec;
 pub use rustc_middle::infer::canonical::*;
-use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 
 use crate::infer::{InferCtxt, RegionVariableOrigin};
@@ -67,30 +67,12 @@ impl<'tcx> InferCtxt<'tcx> {
             .chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
             .collect();
 
-        let canonical_inference_vars =
-            self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
-        let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
-        (result, canonical_inference_vars)
-    }
-
-    /// Given the "infos" about the canonical variables from some
-    /// canonical, creates fresh variables with the same
-    /// characteristics (see `instantiate_canonical_var` for
-    /// details). You can then use `instantiate` to instantiate the
-    /// canonical variable with these inference variables.
-    fn instantiate_canonical_vars(
-        &self,
-        span: Span,
-        variables: &List<CanonicalVarKind<'tcx>>,
-        universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
-    ) -> CanonicalVarValues<'tcx> {
-        CanonicalVarValues {
-            var_values: self.tcx.mk_args_from_iter(
-                variables
-                    .iter()
-                    .map(|kind| self.instantiate_canonical_var(span, kind, &universe_map)),
-            ),
-        }
+        let var_values =
+            CanonicalVarValues::instantiate(self.tcx, &canonical.variables, |var_values, info| {
+                self.instantiate_canonical_var(span, info, &var_values, |ui| universes[ui])
+            });
+        let result = canonical.instantiate(self.tcx, &var_values);
+        (result, var_values)
     }
 
     /// Given the "info" about a canonical variable, creates a fresh
@@ -105,21 +87,27 @@ impl<'tcx> InferCtxt<'tcx> {
         &self,
         span: Span,
         kind: CanonicalVarKind<'tcx>,
+        previous_var_values: &[GenericArg<'tcx>],
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> GenericArg<'tcx> {
         match kind {
-            CanonicalVarKind::Ty(ty_kind) => {
-                let ty = match ty_kind {
-                    CanonicalTyVarKind::General(ui) => {
-                        self.next_ty_var_in_universe(span, universe_map(ui))
+            CanonicalVarKind::Ty { ui, sub_root } => {
+                let vid = self.next_ty_vid_in_universe(span, universe_map(ui));
+                // If this inference variable is related to an earlier variable
+                // via subtyping, we need to add that info to the inference context.
+                if let Some(prev) = previous_var_values.get(sub_root.as_usize()) {
+                    if let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind() {
+                        self.sub_unify_ty_vids_raw(vid, sub_root);
+                    } else {
+                        unreachable!()
                     }
+                }
+                Ty::new_var(self.tcx, vid).into()
+            }
 
-                    CanonicalTyVarKind::Int => self.next_int_var(),
+            CanonicalVarKind::Int => self.next_int_var().into(),
 
-                    CanonicalTyVarKind::Float => self.next_float_var(),
-                };
-                ty.into()
-            }
+            CanonicalVarKind::Float => self.next_float_var().into(),
 
             CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => {
                 let universe_mapped = universe_map(universe);
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 09578598114..5d1b4be9e57 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -13,6 +13,7 @@ use std::iter;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::bug;
+use rustc_middle::infer::canonical::CanonicalVarKind;
 use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
 use tracing::{debug, instrument};
 
@@ -413,26 +414,27 @@ impl<'tcx> InferCtxt<'tcx> {
         let mut opt_values: IndexVec<BoundVar, Option<GenericArg<'tcx>>> =
             IndexVec::from_elem_n(None, query_response.variables.len());
 
-        // In terms of our example above, we are iterating over pairs like:
-        // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
         for (original_value, result_value) in iter::zip(&original_values.var_values, result_values)
         {
             match result_value.kind() {
                 GenericArgKind::Type(result_value) => {
-                    // e.g., here `result_value` might be `?0` in the example above...
-                    if let ty::Bound(debruijn, b) = *result_value.kind() {
-                        // ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
-
+                    // We disable the instantiation guess for inference variables
+                    // and only use it for placeholders. We need to handle the
+                    // `sub_root` of type inference variables which would make this
+                    // more involved. They are also a lot rarer than region variables.
+                    if let ty::Bound(debruijn, b) = *result_value.kind()
+                        && !matches!(
+                            query_response.variables[b.var.as_usize()],
+                            CanonicalVarKind::Ty { .. }
+                        )
+                    {
                         // We only allow a `ty::INNERMOST` index in generic parameters.
                         assert_eq!(debruijn, ty::INNERMOST);
                         opt_values[b.var] = Some(*original_value);
                     }
                 }
                 GenericArgKind::Lifetime(result_value) => {
-                    // e.g., here `result_value` might be `'?1` in the example above...
                     if let ty::ReBound(debruijn, b) = result_value.kind() {
-                        // ... in which case we would set `canonical_vars[0]` to `Some('static)`.
-
                         // We only allow a `ty::INNERMOST` index in generic parameters.
                         assert_eq!(debruijn, ty::INNERMOST);
                         opt_values[b.var] = Some(*original_value);
@@ -440,8 +442,6 @@ impl<'tcx> InferCtxt<'tcx> {
                 }
                 GenericArgKind::Const(result_value) => {
                     if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
-                        // ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
-
                         // We only allow a `ty::INNERMOST` index in generic parameters.
                         assert_eq!(debruijn, ty::INNERMOST);
                         opt_values[b.var] = Some(*original_value);
@@ -453,39 +453,36 @@ impl<'tcx> InferCtxt<'tcx> {
         // Create result arguments: if we found a value for a
         // given variable in the loop above, use that. Otherwise, use
         // a fresh inference variable.
-        let result_args = CanonicalVarValues {
-            var_values: self.tcx.mk_args_from_iter(
-                query_response.variables.iter().enumerate().map(|(index, var_kind)| {
-                    if var_kind.universe() != ty::UniverseIndex::ROOT {
-                        // A variable from inside a binder of the query. While ideally these shouldn't
-                        // exist at all, we have to deal with them for now.
-                        self.instantiate_canonical_var(cause.span, var_kind, |u| {
-                            universe_map[u.as_usize()]
-                        })
-                    } else if var_kind.is_existential() {
-                        match opt_values[BoundVar::new(index)] {
-                            Some(k) => k,
-                            None => self.instantiate_canonical_var(cause.span, var_kind, |u| {
-                                universe_map[u.as_usize()]
-                            }),
-                        }
-                    } else {
-                        // For placeholders which were already part of the input, we simply map this
-                        // universal bound variable back the placeholder of the input.
-                        opt_values[BoundVar::new(index)].expect(
-                            "expected placeholder to be unified with itself during response",
-                        )
-                    }
-                }),
-            ),
-        };
+        let tcx = self.tcx;
+        let variables = query_response.variables;
+        let var_values = CanonicalVarValues::instantiate(tcx, variables, |var_values, kind| {
+            if kind.universe() != ty::UniverseIndex::ROOT {
+                // A variable from inside a binder of the query. While ideally these shouldn't
+                // exist at all, we have to deal with them for now.
+                self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
+                    universe_map[u.as_usize()]
+                })
+            } else if kind.is_existential() {
+                match opt_values[BoundVar::new(var_values.len())] {
+                    Some(k) => k,
+                    None => self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
+                        universe_map[u.as_usize()]
+                    }),
+                }
+            } else {
+                // For placeholders which were already part of the input, we simply map this
+                // universal bound variable back the placeholder of the input.
+                opt_values[BoundVar::new(var_values.len())]
+                    .expect("expected placeholder to be unified with itself during response")
+            }
+        });
 
         let mut obligations = PredicateObligations::new();
 
         // Carry all newly resolved opaque types to the caller's scope
         for &(a, b) in &query_response.value.opaque_types {
-            let a = instantiate_value(self.tcx, &result_args, a);
-            let b = instantiate_value(self.tcx, &result_args, b);
+            let a = instantiate_value(self.tcx, &var_values, a);
+            let b = instantiate_value(self.tcx, &var_values, b);
             debug!(?a, ?b, "constrain opaque type");
             // We use equate here instead of, for example, just registering the
             // opaque type's hidden value directly, because the hidden type may have been an inference
@@ -502,7 +499,7 @@ impl<'tcx> InferCtxt<'tcx> {
             );
         }
 
-        Ok(InferOk { value: result_args, obligations })
+        Ok(InferOk { value: var_values, obligations })
     }
 
     /// Given a "guess" at the values for the canonical variables in
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index bb9c8850093..14cc590720a 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -1,4 +1,4 @@
-///! Definition of `InferCtxtLike` from the librarified type layer.
+//! Definition of `InferCtxtLike` from the librarified type layer.
 use rustc_hir::def_id::DefId;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::relate::RelateResult;
@@ -59,6 +59,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         self.root_var(var)
     }
 
+    fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid {
+        self.sub_unification_table_root_var(var)
+    }
+
     fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
         self.root_const_var(var)
     }
@@ -179,6 +183,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         self.inner.borrow_mut().type_variables().equate(a, b);
     }
 
+    fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
+        self.sub_unify_ty_vids_raw(a, b);
+    }
+
     fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) {
         self.inner.borrow_mut().int_unification_table().union(a, b);
     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index d105d24bed7..9d3886aff1c 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -764,6 +764,7 @@ impl<'tcx> InferCtxt<'tcx> {
         let r_b = self.shallow_resolve(predicate.skip_binder().b);
         match (r_a.kind(), r_b.kind()) {
             (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
+                self.sub_unify_ty_vids_raw(a_vid, b_vid);
                 return Err((a_vid, b_vid));
             }
             _ => {}
@@ -1128,6 +1129,14 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow_mut().type_variables().root_var(var)
     }
 
+    pub fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
+        self.inner.borrow_mut().type_variables().sub_unify(a, b);
+    }
+
+    pub fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid {
+        self.inner.borrow_mut().type_variables().sub_unification_table_root_var(var)
+    }
+
     pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
         self.inner.borrow_mut().const_unification_table().find(var).vid
     }
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index a000bb1123c..cc41957c110 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -6,8 +6,8 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
-    self, AliasRelationDirection, InferConst, MaxUniverse, Term, Ty, TyCtxt, TypeVisitable,
-    TypeVisitableExt, TypingMode,
+    self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_span::Span;
 use tracing::{debug, instrument, warn};
@@ -290,6 +290,45 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 }
 
+/// Finds the max universe present
+struct MaxUniverse {
+    max_universe: ty::UniverseIndex,
+}
+
+impl MaxUniverse {
+    fn new() -> Self {
+        MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
+    }
+
+    fn max_universe(self) -> ty::UniverseIndex {
+        self.max_universe
+    }
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
+    fn visit_ty(&mut self, t: Ty<'tcx>) {
+        if let ty::Placeholder(placeholder) = t.kind() {
+            self.max_universe = self.max_universe.max(placeholder.universe);
+        }
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: ty::Const<'tcx>) {
+        if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
+            self.max_universe = self.max_universe.max(placeholder.universe);
+        }
+
+        c.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) {
+        if let ty::RePlaceholder(placeholder) = r.kind() {
+            self.max_universe = self.max_universe.max(placeholder.universe);
+        }
+    }
+}
+
 /// The "generalizer" is used when handling inference variables.
 ///
 /// The basic strategy for handling a constraint like `?A <: B` is to
@@ -519,6 +558,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
                             let origin = inner.type_variables().var_origin(vid);
                             let new_var_id =
                                 inner.type_variables().new_var(self.for_universe, origin);
+                            // Record that `vid` and `new_var_id` have to be subtypes
+                            // of each other. This is currently only used for diagnostics.
+                            // To see why, see the docs in the `type_variables` module.
+                            inner.type_variables().sub_unify(vid, new_var_id);
                             // If we're in the new solver and create a new inference
                             // variable inside of an alias we eagerly constrain that
                             // inference variable to prevent unexpected ambiguity errors.
diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
index fcc0ab3af41..22c815fb87c 100644
--- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
@@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> {
 pub(crate) enum UndoLog<'tcx> {
     DuplicateOpaqueType,
     OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
-    TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
+    TypeVariables(type_variable::UndoLog<'tcx>),
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
@@ -49,6 +49,8 @@ impl_from! {
     RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
 
     TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
+    TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidSubKey>>),
+    TypeVariables(type_variable::UndoLog<'tcx>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
 
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 6f6791804d3..65f77fe8e25 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -13,12 +13,48 @@ use tracing::debug;
 
 use crate::infer::InferCtxtUndoLogs;
 
+/// Represents a single undo-able action that affects a type inference variable.
+#[derive(Clone)]
+pub(crate) enum UndoLog<'tcx> {
+    EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>),
+    SubRelation(sv::UndoLog<ut::Delegate<TyVidSubKey>>),
+}
+
+/// Convert from a specific kind of undo to the more general UndoLog
+impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self {
+        UndoLog::EqRelation(l)
+    }
+}
+
+/// Convert from a specific kind of undo to the more general UndoLog
+impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidSubKey>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<TyVidSubKey>>) -> Self {
+        UndoLog::SubRelation(l)
+    }
+}
+
 impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariableStorage<'tcx> {
     fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) {
         self.eq_relations.reverse(undo)
     }
 }
 
+impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidSubKey>>> for TypeVariableStorage<'tcx> {
+    fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidSubKey>>) {
+        self.sub_unification_table.reverse(undo)
+    }
+}
+
+impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> {
+    fn reverse(&mut self, undo: UndoLog<'tcx>) {
+        match undo {
+            UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo),
+            UndoLog::SubRelation(undo) => self.sub_unification_table.reverse(undo),
+        }
+    }
+}
+
 #[derive(Clone, Default)]
 pub(crate) struct TypeVariableStorage<'tcx> {
     /// The origins of each type variable.
@@ -27,6 +63,25 @@ pub(crate) struct TypeVariableStorage<'tcx> {
     /// constraint `?X == ?Y`. This table also stores, for each key,
     /// the known value.
     eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>,
+    /// Only used by `-Znext-solver` and for diagnostics. Tracks whether
+    /// type variables are related via subtyping at all, ignoring which of
+    /// the two is the subtype.
+    ///
+    /// When reporting ambiguity errors, we sometimes want to
+    /// treat all inference vars which are subtypes of each
+    /// others as if they are equal. For this case we compute
+    /// the transitive closure of our subtype obligations here.
+    ///
+    /// E.g. when encountering ambiguity errors, we want to suggest
+    /// specifying some method argument or to add a type annotation
+    /// to a local variable. Because subtyping cannot change the
+    /// shape of a type, it's fine if the cause of the ambiguity error
+    /// is only related to the suggested variable via subtyping.
+    ///
+    /// Even for something like `let x = returns_arg(); x.method();` the
+    /// type of `x` is only a supertype of the argument of `returns_arg`. We
+    /// still want to suggest specifying the type of the argument.
+    sub_unification_table: ut::UnificationTableStorage<TyVidSubKey>,
 }
 
 pub(crate) struct TypeVariableTable<'a, 'tcx> {
@@ -102,13 +157,24 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
         self.storage.values[vid].origin
     }
 
-    /// Records that `a == b`, depending on `dir`.
+    /// Records that `a == b`.
     ///
     /// Precondition: neither `a` nor `b` are known.
     pub(crate) fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
         debug_assert!(self.probe(a).is_unknown());
         debug_assert!(self.probe(b).is_unknown());
         self.eq_relations().union(a, b);
+        self.sub_unification_table().union(a, b);
+    }
+
+    /// Records that `a` and `b` are related via subtyping. We don't track
+    /// which of the two is the subtype.
+    ///
+    /// Precondition: neither `a` nor `b` are known.
+    pub(crate) fn sub_unify(&mut self, a: ty::TyVid, b: ty::TyVid) {
+        debug_assert!(self.probe(a).is_unknown());
+        debug_assert!(self.probe(b).is_unknown());
+        self.sub_unification_table().union(a, b);
     }
 
     /// Instantiates `vid` with the type `ty`.
@@ -142,6 +208,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
         origin: TypeVariableOrigin,
     ) -> ty::TyVid {
         let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
+
+        let sub_key = self.sub_unification_table().new_key(());
+        debug_assert_eq!(eq_key.vid, sub_key.vid);
+
         let index = self.storage.values.push(TypeVariableData { origin });
         debug_assert_eq!(eq_key.vid, index);
 
@@ -164,6 +234,18 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
         self.eq_relations().find(vid).vid
     }
 
+    /// Returns the "root" variable of `vid` in the `sub_unification_table`
+    /// equivalence table. All type variables that have been are related via
+    /// equality or subtyping will yield the same root variable (per the
+    /// union-find algorithm), so `sub_unification_table_root_var(a)
+    /// == sub_unification_table_root_var(b)` implies that:
+    /// ```text
+    /// exists X. (a <: X || X <: a) && (b <: X || X <: b)
+    /// ```
+    pub(crate) fn sub_unification_table_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
+        self.sub_unification_table().find(vid).vid
+    }
+
     /// Retrieves the type to which `vid` has been instantiated, if
     /// any.
     pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
@@ -181,6 +263,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
         self.storage.eq_relations.with_log(self.undo_log)
     }
 
+    #[inline]
+    fn sub_unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidSubKey> {
+        self.storage.sub_unification_table.with_log(self.undo_log)
+    }
+
     /// Returns a range of the type variables created during the snapshot.
     pub(crate) fn vars_since_snapshot(
         &mut self,
@@ -243,6 +330,33 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> {
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) struct TyVidSubKey {
+    vid: ty::TyVid,
+}
+
+impl From<ty::TyVid> for TyVidSubKey {
+    #[inline] // make this function eligible for inlining - it is quite hot.
+    fn from(vid: ty::TyVid) -> Self {
+        TyVidSubKey { vid }
+    }
+}
+
+impl ut::UnifyKey for TyVidSubKey {
+    type Value = ();
+    #[inline]
+    fn index(&self) -> u32 {
+        self.vid.as_u32()
+    }
+    #[inline]
+    fn from_index(i: u32) -> TyVidSubKey {
+        TyVidSubKey { vid: ty::TyVid::from_u32(i) }
+    }
+    fn tag() -> &'static str {
+        "TyVidSubKey"
+    }
+}
+
 impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
     type Error = ut::NoError;
 
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 4b9c71d7172..d83b18cbc2d 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -30,10 +30,6 @@ interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
 interface_input_file_would_be_overwritten =
     the input file "{$path}" would be overwritten by the generated executable
 
-interface_limit_invalid =
-    `limit` must be a non-negative integer
-    .label = {$error_str}
-
 interface_mixed_bin_crate =
     cannot mix `bin` crate type with others
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 6b39b4f1891..d1082eaf617 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -108,13 +108,3 @@ pub(crate) struct AbiRequiredTargetFeature<'a> {
     pub feature: &'a str,
     pub enabled: &'a str,
 }
-
-#[derive(Diagnostic)]
-#[diag(interface_limit_invalid)]
-pub(crate) struct LimitInvalid<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub value_span: Span,
-    pub error_str: &'a str,
-}
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 8f131f45bbd..4c820b8877b 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -13,7 +13,7 @@ use rustc_lint::LintStore;
 use rustc_middle::ty;
 use rustc_middle::ty::CurrentGcx;
 use rustc_middle::util::Providers;
-use rustc_parse::new_parser_from_source_str;
+use rustc_parse::new_parser_from_simple_source_str;
 use rustc_parse::parser::attr::AllowLeadingUnsafe;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
@@ -68,7 +68,7 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
                 };
             }
 
-            match new_parser_from_source_str(&psess, filename, s.to_string()) {
+            match new_parser_from_simple_source_str(&psess, filename, s.to_string()) {
                 Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) {
                     Ok(meta_item) if parser.token == token::Eof => {
                         if meta_item.path.segments.len() != 1 {
@@ -166,7 +166,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
             error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
         };
 
-        let mut parser = match new_parser_from_source_str(&psess, filename, s.to_string()) {
+        let mut parser = match new_parser_from_simple_source_str(&psess, filename, s.to_string()) {
             Ok(parser) => parser,
             Err(errs) => {
                 errs.into_iter().for_each(|err| err.cancel());
diff --git a/compiler/rustc_interface/src/limits.rs b/compiler/rustc_interface/src/limits.rs
index 8f01edec09f..10e58f32256 100644
--- a/compiler/rustc_interface/src/limits.rs
+++ b/compiler/rustc_interface/src/limits.rs
@@ -8,78 +8,32 @@
 //! Users can override these limits via an attribute on the crate like
 //! `#![recursion_limit="22"]`. This pass just looks for those attributes.
 
-use std::num::IntErrorKind;
-
-use rustc_ast::attr::AttributeExt;
-use rustc_middle::bug;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::limit::Limit;
+use rustc_hir::{Attribute, find_attr};
 use rustc_middle::query::Providers;
-use rustc_session::{Limit, Limits, Session};
-use rustc_span::{Symbol, sym};
-
-use crate::errors::LimitInvalid;
+use rustc_session::Limits;
 
 pub(crate) fn provide(providers: &mut Providers) {
-    providers.limits = |tcx, ()| Limits {
-        recursion_limit: get_recursion_limit(tcx.hir_krate_attrs(), tcx.sess),
-        move_size_limit: get_limit(
-            tcx.hir_krate_attrs(),
-            tcx.sess,
-            sym::move_size_limit,
-            Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0)),
-        ),
-        type_length_limit: get_limit(
-            tcx.hir_krate_attrs(),
-            tcx.sess,
-            sym::type_length_limit,
-            Limit::new(2usize.pow(24)),
-        ),
-        pattern_complexity_limit: get_limit(
-            tcx.hir_krate_attrs(),
-            tcx.sess,
-            sym::pattern_complexity_limit,
-            Limit::unlimited(),
-        ),
+    providers.limits = |tcx, ()| {
+        let attrs = tcx.hir_krate_attrs();
+        Limits {
+            recursion_limit: get_recursion_limit(tcx.hir_krate_attrs()),
+            move_size_limit:
+                find_attr!(attrs, AttributeKind::MoveSizeLimit { limit, .. } => *limit)
+                    .unwrap_or(Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0))),
+            type_length_limit:
+                find_attr!(attrs, AttributeKind::TypeLengthLimit { limit, .. } => *limit)
+                    .unwrap_or(Limit::new(2usize.pow(24))),
+            pattern_complexity_limit:
+                find_attr!(attrs, AttributeKind::PatternComplexityLimit { limit, .. } => *limit)
+                    .unwrap_or(Limit::unlimited()),
+        }
     }
 }
 
 // This one is separate because it must be read prior to macro expansion.
-pub(crate) fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit {
-    get_limit(krate_attrs, sess, sym::recursion_limit, Limit::new(128))
-}
-
-fn get_limit(
-    krate_attrs: &[impl AttributeExt],
-    sess: &Session,
-    name: Symbol,
-    default: Limit,
-) -> Limit {
-    for attr in krate_attrs {
-        if !attr.has_name(name) {
-            continue;
-        }
-
-        if let Some(sym) = attr.value_str() {
-            match sym.as_str().parse() {
-                Ok(n) => return Limit::new(n),
-                Err(e) => {
-                    let error_str = match e.kind() {
-                        IntErrorKind::PosOverflow => "`limit` is too large",
-                        IntErrorKind::Empty => "`limit` must be a non-negative integer",
-                        IntErrorKind::InvalidDigit => "not a valid integer",
-                        IntErrorKind::NegOverflow => {
-                            bug!("`limit` should never negatively overflow")
-                        }
-                        IntErrorKind::Zero => bug!("zero is a valid `limit`"),
-                        kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
-                    };
-                    sess.dcx().emit_err(LimitInvalid {
-                        span: attr.span(),
-                        value_span: attr.value_span().unwrap(),
-                        error_str,
-                    });
-                }
-            }
-        }
-    }
-    default
+pub(crate) fn get_recursion_limit(attrs: &[Attribute]) -> Limit {
+    find_attr!(attrs, AttributeKind::RecursionLimit { limit, .. } => *limit)
+        .unwrap_or(Limit::new(128))
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index ca8c10311fb..6d9751d7d4d 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -6,7 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock};
 use std::{env, fs, iter};
 
 use rustc_ast as ast;
-use rustc_attr_parsing::{AttributeParser, ShouldEmit, validate_attr};
+use rustc_attr_parsing::{AttributeParser, ShouldEmit};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::jobserver::Proxy;
 use rustc_data_structures::steal::Steal;
@@ -19,6 +19,7 @@ use rustc_fs_util::try_canonicalize;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
 use rustc_hir::definitions::Definitions;
+use rustc_hir::limit::Limit;
 use rustc_incremental::setup_dep_graph;
 use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
 use rustc_metadata::EncodedMetadata;
@@ -30,12 +31,12 @@ use rustc_middle::util::Providers;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_passes::{abi_test, input_stats, layout_test};
 use rustc_resolve::{Resolver, ResolverOutputs};
+use rustc_session::Session;
 use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
 use rustc_session::cstore::Untracked;
 use rustc_session::output::{collect_crate_types, filename_for_input};
 use rustc_session::parse::feature_err;
 use rustc_session::search_paths::PathKind;
-use rustc_session::{Limit, Session};
 use rustc_span::{
     DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
     Symbol, sym,
@@ -1246,7 +1247,8 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol
     // in all code paths that require the crate name very early on, namely before
     // macro expansion.
 
-    let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal);
+    let attr_crate_name =
+        parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal { also_emit_lints: true });
 
     let validate = |name, span| {
         rustc_session::output::validate_crate_name(sess, name, span);
@@ -1307,36 +1309,18 @@ pub(crate) fn parse_crate_name(
 }
 
 fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
-    // We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`])
-    // because that would require expanding this while in the middle of expansion, which needs to
-    // know the limit before expanding.
-    let _ = validate_and_find_value_str_builtin_attr(sym::recursion_limit, sess, krate_attrs);
-    crate::limits::get_recursion_limit(krate_attrs, sess)
-}
-
-/// Validate *all* occurrences of the given "[value-str]" built-in attribute and return the first find.
-///
-/// This validator is intended for built-in attributes whose value needs to be known very early
-/// during compilation (namely, before macro expansion) and it mainly exists to reject macro calls
-/// inside of the attributes, such as in `#![name = expand!()]`. Normal attribute validation happens
-/// during semantic analysis via [`TyCtxt::check_mod_attrs`] which happens *after* macro expansion
-/// when such macro calls (here: `expand`) have already been expanded and we can no longer check for
-/// their presence.
-///
-/// [value-str]: ast::Attribute::value_str
-fn validate_and_find_value_str_builtin_attr(
-    name: Symbol,
-    sess: &Session,
-    krate_attrs: &[ast::Attribute],
-) -> Option<(Symbol, Span)> {
-    let mut result = None;
-    // Validate *all* relevant attributes, not just the first occurrence.
-    for attr in ast::attr::filter_by_name(krate_attrs, name) {
-        let Some(value) = attr.value_str() else {
-            validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, attr, name)
-        };
-        // Choose the first occurrence as our result.
-        result.get_or_insert((value, attr.span));
-    }
-    result
+    let attr = AttributeParser::parse_limited_should_emit(
+        sess,
+        &krate_attrs,
+        sym::recursion_limit,
+        DUMMY_SP,
+        rustc_ast::node_id::CRATE_NODE_ID,
+        None,
+        // errors are fatal here, but lints aren't.
+        // If things aren't fatal we continue, and will parse this again.
+        // That makes the same lint trigger again.
+        // So, no lints here to avoid duplicates.
+        ShouldEmit::EarlyFatal { also_emit_lints: false },
+    );
+    crate::limits::get_recursion_limit(attr.as_slice())
 }
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 7718f16984d..3a50aac50cb 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
+bitflags = "2.4.1"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 3267e70f1de..ad73e15e31f 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -136,7 +136,6 @@ impl ClashingExternDeclarations {
             ty::TypingEnv::non_body_analysis(tcx, this_fi.owner_id),
             existing_decl_ty,
             this_decl_ty,
-            types::CItemKind::Declaration,
         ) {
             let orig = name_of_extern_decl(tcx, existing_did);
 
@@ -214,10 +213,9 @@ fn structurally_same_type<'tcx>(
     typing_env: ty::TypingEnv<'tcx>,
     a: Ty<'tcx>,
     b: Ty<'tcx>,
-    ckind: types::CItemKind,
 ) -> bool {
     let mut seen_types = UnordSet::default();
-    let result = structurally_same_type_impl(&mut seen_types, tcx, typing_env, a, b, ckind);
+    let result = structurally_same_type_impl(&mut seen_types, tcx, typing_env, a, b);
     if cfg!(debug_assertions) && result {
         // Sanity-check: must have same ABI, size and alignment.
         // `extern` blocks cannot be generic, so we'll always get a layout here.
@@ -236,7 +234,6 @@ fn structurally_same_type_impl<'tcx>(
     typing_env: ty::TypingEnv<'tcx>,
     a: Ty<'tcx>,
     b: Ty<'tcx>,
-    ckind: types::CItemKind,
 ) -> bool {
     debug!("structurally_same_type_impl(tcx, a = {:?}, b = {:?})", a, b);
 
@@ -307,7 +304,6 @@ fn structurally_same_type_impl<'tcx>(
                                 typing_env,
                                 tcx.type_of(a_did).instantiate(tcx, a_gen_args),
                                 tcx.type_of(b_did).instantiate(tcx, b_gen_args),
-                                ckind,
                             )
                         },
                     )
@@ -315,25 +311,19 @@ fn structurally_same_type_impl<'tcx>(
                 (ty::Array(a_ty, a_len), ty::Array(b_ty, b_len)) => {
                     // For arrays, we also check the length.
                     a_len == b_len
-                        && structurally_same_type_impl(
-                            seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
-                        )
+                        && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
                 }
                 (ty::Slice(a_ty), ty::Slice(b_ty)) => {
-                    structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind)
+                    structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
                 }
                 (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
                     a_mutbl == b_mutbl
-                        && structurally_same_type_impl(
-                            seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
-                        )
+                        && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
                 }
                 (ty::Ref(_a_region, a_ty, a_mut), ty::Ref(_b_region, b_ty, b_mut)) => {
                     // For structural sameness, we don't need the region to be same.
                     a_mut == b_mut
-                        && structurally_same_type_impl(
-                            seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
-                        )
+                        && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
                 }
                 (ty::FnDef(..), ty::FnDef(..)) => {
                     let a_poly_sig = a.fn_sig(tcx);
@@ -347,7 +337,7 @@ fn structurally_same_type_impl<'tcx>(
                     (a_sig.abi, a_sig.safety, a_sig.c_variadic)
                         == (b_sig.abi, b_sig.safety, b_sig.c_variadic)
                         && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
-                            structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b, ckind)
+                            structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b)
                         })
                         && structurally_same_type_impl(
                             seen_types,
@@ -355,7 +345,6 @@ fn structurally_same_type_impl<'tcx>(
                             typing_env,
                             a_sig.output(),
                             b_sig.output(),
-                            ckind,
                         )
                 }
                 (ty::Tuple(..), ty::Tuple(..)) => {
@@ -383,14 +372,14 @@ fn structurally_same_type_impl<'tcx>(
                 // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
                 // enum layout optimisation is being applied.
                 (ty::Adt(..) | ty::Pat(..), _) if is_primitive_or_pointer(b) => {
-                    if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) {
+                    if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a) {
                         a_inner == b
                     } else {
                         false
                     }
                 }
                 (_, ty::Adt(..) | ty::Pat(..)) if is_primitive_or_pointer(a) => {
-                    if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) {
+                    if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b) {
                         b_inner == a
                     } else {
                         false
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index bdbac7fc4d1..9bb53fea54a 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -194,8 +194,7 @@ late_lint_methods!(
             DefaultCouldBeDerived: DefaultCouldBeDerived::default(),
             DerefIntoDynSupertrait: DerefIntoDynSupertrait,
             DropForgetUseless: DropForgetUseless,
-            ImproperCTypesDeclarations: ImproperCTypesDeclarations,
-            ImproperCTypesDefinitions: ImproperCTypesDefinitions,
+            ImproperCTypesLint: ImproperCTypesLint,
             InvalidFromUtf8: InvalidFromUtf8,
             VariantSizeDifferences: VariantSizeDifferences,
             PathStatements: PathStatements,
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index f8a692313f0..a72b802eb5d 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1,35 +1,28 @@
 use std::iter;
-use std::ops::ControlFlow;
 
-use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::DiagMessage;
-use rustc_hir::intravisit::VisitorExt;
-use rustc_hir::{AmbigArg, Expr, ExprKind, HirId, LangItem};
+use rustc_abi::{BackendRepr, TagEncoding, Variants, WrappingRange};
+use rustc_hir::{Expr, ExprKind, HirId, LangItem};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
-use rustc_middle::ty::{
-    self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, Symbol, sym};
 use tracing::debug;
 use {rustc_ast as ast, rustc_hir as hir};
 
-mod improper_ctypes;
+mod improper_ctypes; // these filed do the implementation for ImproperCTypesDefinitions,ImproperCTypesDeclarations
+pub(crate) use improper_ctypes::ImproperCTypesLint;
 
 use crate::lints::{
     AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
     AmbiguousWidePointerComparisonsAddrSuggestion, AmbiguousWidePointerComparisonsCastSuggestion,
     AmbiguousWidePointerComparisonsExpectSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
-    AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
+    AtomicOrderingStore, InvalidAtomicOrderingDiag, InvalidNanComparisons,
     InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
-    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment,
+    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
     VariantSizeDifferencesDiag,
 };
-use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
+use crate::{LateContext, LateLintPass, LintContext};
 
 mod literal;
 
@@ -690,144 +683,6 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
     }
 }
 
-declare_lint! {
-    /// The `improper_ctypes` lint detects incorrect use of types in foreign
-    /// modules.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// unsafe extern "C" {
-    ///     static STATIC: String;
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// The compiler has several checks to verify that types used in `extern`
-    /// blocks are safe and follow certain rules to ensure proper
-    /// compatibility with the foreign interfaces. This lint is issued when it
-    /// detects a probable mistake in a definition. The lint usually should
-    /// provide a description of the issue, along with possibly a hint on how
-    /// to resolve it.
-    IMPROPER_CTYPES,
-    Warn,
-    "proper use of libc types in foreign modules"
-}
-
-declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
-
-declare_lint! {
-    /// The `improper_ctypes_definitions` lint detects incorrect use of
-    /// [`extern` function] definitions.
-    ///
-    /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// # #![allow(unused)]
-    /// pub extern "C" fn str_type(p: &str) { }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// There are many parameter and return types that may be specified in an
-    /// `extern` function that are not compatible with the given ABI. This
-    /// lint is an alert that these types should not be used. The lint usually
-    /// should provide a description of the issue, along with possibly a hint
-    /// on how to resolve it.
-    IMPROPER_CTYPES_DEFINITIONS,
-    Warn,
-    "proper use of libc types in foreign item definitions"
-}
-
-declare_lint! {
-    /// The `uses_power_alignment` lint detects specific `repr(C)`
-    /// aggregates on AIX.
-    /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
-    /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
-    /// which can also be set for XLC by `#pragma align(power)` or
-    /// `-qalign=power`. Aggregates with a floating-point type as the
-    /// recursively first field (as in "at offset 0") modify the layout of
-    /// *subsequent* fields of the associated structs to use an alignment value
-    /// where the floating-point type is aligned on a 4-byte boundary.
-    ///
-    /// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
-    /// would be unsound to do in a `repr(C)` type without all the restrictions that come with
-    /// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
-    /// expense of incompatibility with C code.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
-    /// #[repr(C)]
-    /// pub struct Floats {
-    ///     a: f64,
-    ///     b: u8,
-    ///     c: f64,
-    /// }
-    /// ```
-    ///
-    /// This will produce:
-    ///
-    /// ```text
-    /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
-    ///  --> <source>:5:3
-    ///   |
-    /// 5 |   c: f64,
-    ///   |   ^^^^^^
-    ///   |
-    ///   = note: `#[warn(uses_power_alignment)]` on by default
-    /// ```
-    ///
-    /// ### Explanation
-    ///
-    /// The power alignment rule specifies that the above struct has the
-    /// following alignment:
-    ///  - offset_of!(Floats, a) == 0
-    ///  - offset_of!(Floats, b) == 8
-    ///  - offset_of!(Floats, c) == 12
-    ///
-    /// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
-    /// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
-    /// Thus, a warning is produced for the above struct.
-    USES_POWER_ALIGNMENT,
-    Warn,
-    "Structs do not follow the power alignment rule under repr(C)"
-}
-
-declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]);
-
-#[derive(Clone, Copy)]
-pub(crate) enum CItemKind {
-    Declaration,
-    Definition,
-}
-
-struct ImproperCTypesVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    mode: CItemKind,
-}
-
-/// Accumulator for recursive ffi type checking
-struct CTypesVisitorState<'tcx> {
-    cache: FxHashSet<Ty<'tcx>>,
-    /// The original type being checked, before we recursed
-    /// to any other types it contains.
-    base_ty: Ty<'tcx>,
-}
-
-enum FfiResult<'tcx> {
-    FfiSafe,
-    FfiPhantom(Ty<'tcx>),
-    FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
-}
-
 pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::AdtDef<'tcx>,
@@ -855,14 +710,13 @@ fn ty_is_known_nonnull<'tcx>(
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
-    mode: CItemKind,
 ) -> bool {
     let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
 
     match ty.kind() {
         ty::FnPtr(..) => true,
         ty::Ref(..) => true,
-        ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true,
+        ty::Adt(def, _) if def.is_box() => true,
         ty::Adt(def, args) if def.repr().transparent() && !def.is_union() => {
             let marked_non_null = nonnull_optimization_guaranteed(tcx, *def);
 
@@ -878,10 +732,10 @@ fn ty_is_known_nonnull<'tcx>(
             def.variants()
                 .iter()
                 .filter_map(|variant| transparent_newtype_field(tcx, variant))
-                .any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args), mode))
+                .any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args)))
         }
         ty::Pat(base, pat) => {
-            ty_is_known_nonnull(tcx, typing_env, *base, mode)
+            ty_is_known_nonnull(tcx, typing_env, *base)
                 || pat_ty_is_known_nonnull(tcx, typing_env, *pat)
         }
         _ => false,
@@ -992,7 +846,6 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
-    ckind: CItemKind,
 ) -> Option<Ty<'tcx>> {
     debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty);
     match ty.kind() {
@@ -1017,7 +870,7 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
                 _ => return None,
             };
 
-            if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) {
+            if !ty_is_known_nonnull(tcx, typing_env, field_ty) {
                 return None;
             }
 
@@ -1076,710 +929,6 @@ fn get_nullable_type_from_pat<'tcx>(
     }
 }
 
-impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
-    /// Check if the type is array and emit an unsafe type lint.
-    fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
-        if let ty::Array(..) = ty.kind() {
-            self.emit_ffi_unsafe_type_lint(
-                ty,
-                sp,
-                fluent::lint_improper_ctypes_array_reason,
-                Some(fluent::lint_improper_ctypes_array_help),
-            );
-            true
-        } else {
-            false
-        }
-    }
-
-    /// Checks if the given field's type is "ffi-safe".
-    fn check_field_type_for_ffi(
-        &self,
-        acc: &mut CTypesVisitorState<'tcx>,
-        field: &ty::FieldDef,
-        args: GenericArgsRef<'tcx>,
-    ) -> FfiResult<'tcx> {
-        let field_ty = field.ty(self.cx.tcx, args);
-        let field_ty = self
-            .cx
-            .tcx
-            .try_normalize_erasing_regions(self.cx.typing_env(), field_ty)
-            .unwrap_or(field_ty);
-        self.check_type_for_ffi(acc, field_ty)
-    }
-
-    /// Checks if the given `VariantDef`'s field types are "ffi-safe".
-    fn check_variant_for_ffi(
-        &self,
-        acc: &mut CTypesVisitorState<'tcx>,
-        ty: Ty<'tcx>,
-        def: ty::AdtDef<'tcx>,
-        variant: &ty::VariantDef,
-        args: GenericArgsRef<'tcx>,
-    ) -> FfiResult<'tcx> {
-        use FfiResult::*;
-        let transparent_with_all_zst_fields = if def.repr().transparent() {
-            if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
-                // Transparent newtypes have at most one non-ZST field which needs to be checked..
-                match self.check_field_type_for_ffi(acc, field, args) {
-                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
-                    r => return r,
-                }
-
-                false
-            } else {
-                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
-                // `PhantomData`).
-                true
-            }
-        } else {
-            false
-        };
-
-        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
-        let mut all_phantom = !variant.fields.is_empty();
-        for field in &variant.fields {
-            all_phantom &= match self.check_field_type_for_ffi(acc, field, args) {
-                FfiSafe => false,
-                // `()` fields are FFI-safe!
-                FfiUnsafe { ty, .. } if ty.is_unit() => false,
-                FfiPhantom(..) => true,
-                r @ FfiUnsafe { .. } => return r,
-            }
-        }
-
-        if all_phantom {
-            FfiPhantom(ty)
-        } else if transparent_with_all_zst_fields {
-            FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
-        } else {
-            FfiSafe
-        }
-    }
-
-    /// Checks if the given type is "ffi-safe" (has a stable, well-defined
-    /// representation which can be exported to C code).
-    fn check_type_for_ffi(
-        &self,
-        acc: &mut CTypesVisitorState<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> FfiResult<'tcx> {
-        use FfiResult::*;
-
-        let tcx = self.cx.tcx;
-
-        // Protect against infinite recursion, for example
-        // `struct S(*mut S);`.
-        // FIXME: A recursion limit is necessary as well, for irregular
-        // recursive types.
-        if !acc.cache.insert(ty) {
-            return FfiSafe;
-        }
-
-        match *ty.kind() {
-            ty::Adt(def, args) => {
-                if let Some(boxed) = ty.boxed_ty()
-                    && matches!(self.mode, CItemKind::Definition)
-                {
-                    if boxed.is_sized(tcx, self.cx.typing_env()) {
-                        return FfiSafe;
-                    } else {
-                        return FfiUnsafe {
-                            ty,
-                            reason: fluent::lint_improper_ctypes_box,
-                            help: None,
-                        };
-                    }
-                }
-                if def.is_phantom_data() {
-                    return FfiPhantom(ty);
-                }
-                match def.adt_kind() {
-                    AdtKind::Struct | AdtKind::Union => {
-                        if let Some(sym::cstring_type | sym::cstr_type) =
-                            tcx.get_diagnostic_name(def.did())
-                            && !acc.base_ty.is_mutable_ptr()
-                        {
-                            return FfiUnsafe {
-                                ty,
-                                reason: fluent::lint_improper_ctypes_cstr_reason,
-                                help: Some(fluent::lint_improper_ctypes_cstr_help),
-                            };
-                        }
-
-                        if !def.repr().c() && !def.repr().transparent() {
-                            return FfiUnsafe {
-                                ty,
-                                reason: if def.is_struct() {
-                                    fluent::lint_improper_ctypes_struct_layout_reason
-                                } else {
-                                    fluent::lint_improper_ctypes_union_layout_reason
-                                },
-                                help: if def.is_struct() {
-                                    Some(fluent::lint_improper_ctypes_struct_layout_help)
-                                } else {
-                                    Some(fluent::lint_improper_ctypes_union_layout_help)
-                                },
-                            };
-                        }
-
-                        if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
-                            return FfiUnsafe {
-                                ty,
-                                reason: if def.is_struct() {
-                                    fluent::lint_improper_ctypes_struct_non_exhaustive
-                                } else {
-                                    fluent::lint_improper_ctypes_union_non_exhaustive
-                                },
-                                help: None,
-                            };
-                        }
-
-                        if def.non_enum_variant().fields.is_empty() {
-                            return FfiUnsafe {
-                                ty,
-                                reason: if def.is_struct() {
-                                    fluent::lint_improper_ctypes_struct_fieldless_reason
-                                } else {
-                                    fluent::lint_improper_ctypes_union_fieldless_reason
-                                },
-                                help: if def.is_struct() {
-                                    Some(fluent::lint_improper_ctypes_struct_fieldless_help)
-                                } else {
-                                    Some(fluent::lint_improper_ctypes_union_fieldless_help)
-                                },
-                            };
-                        }
-
-                        self.check_variant_for_ffi(acc, ty, def, def.non_enum_variant(), args)
-                    }
-                    AdtKind::Enum => {
-                        if def.variants().is_empty() {
-                            // Empty enums are okay... although sort of useless.
-                            return FfiSafe;
-                        }
-                        // Check for a repr() attribute to specify the size of the
-                        // discriminant.
-                        if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
-                        {
-                            // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
-                            if let Some(ty) =
-                                repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty, self.mode)
-                            {
-                                return self.check_type_for_ffi(acc, ty);
-                            }
-
-                            return FfiUnsafe {
-                                ty,
-                                reason: fluent::lint_improper_ctypes_enum_repr_reason,
-                                help: Some(fluent::lint_improper_ctypes_enum_repr_help),
-                            };
-                        }
-
-                        use improper_ctypes::check_non_exhaustive_variant;
-
-                        let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
-                        // Check the contained variants.
-                        let ret = def.variants().iter().try_for_each(|variant| {
-                            check_non_exhaustive_variant(non_exhaustive, variant)
-                                .map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
-
-                            match self.check_variant_for_ffi(acc, ty, def, variant, args) {
-                                FfiSafe => ControlFlow::Continue(()),
-                                r => ControlFlow::Break(r),
-                            }
-                        });
-                        if let ControlFlow::Break(result) = ret {
-                            return result;
-                        }
-
-                        FfiSafe
-                    }
-                }
-            }
-
-            ty::Char => FfiUnsafe {
-                ty,
-                reason: fluent::lint_improper_ctypes_char_reason,
-                help: Some(fluent::lint_improper_ctypes_char_help),
-            },
-
-            // It's just extra invariants on the type that you need to uphold,
-            // but only the base type is relevant for being representable in FFI.
-            ty::Pat(base, ..) => self.check_type_for_ffi(acc, base),
-
-            // Primitive types with a stable representation.
-            ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
-
-            ty::Slice(_) => FfiUnsafe {
-                ty,
-                reason: fluent::lint_improper_ctypes_slice_reason,
-                help: Some(fluent::lint_improper_ctypes_slice_help),
-            },
-
-            ty::Dynamic(..) => {
-                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
-            }
-
-            ty::Str => FfiUnsafe {
-                ty,
-                reason: fluent::lint_improper_ctypes_str_reason,
-                help: Some(fluent::lint_improper_ctypes_str_help),
-            },
-
-            ty::Tuple(..) => FfiUnsafe {
-                ty,
-                reason: fluent::lint_improper_ctypes_tuple_reason,
-                help: Some(fluent::lint_improper_ctypes_tuple_help),
-            },
-
-            ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
-                if {
-                    matches!(self.mode, CItemKind::Definition)
-                        && ty.is_sized(self.cx.tcx, self.cx.typing_env())
-                } =>
-            {
-                FfiSafe
-            }
-
-            ty::RawPtr(ty, _)
-                if match ty.kind() {
-                    ty::Tuple(tuple) => tuple.is_empty(),
-                    _ => false,
-                } =>
-            {
-                FfiSafe
-            }
-
-            ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty),
-
-            ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty),
-
-            ty::FnPtr(sig_tys, hdr) => {
-                let sig = sig_tys.with(hdr);
-                if sig.abi().is_rustic_abi() {
-                    return FfiUnsafe {
-                        ty,
-                        reason: fluent::lint_improper_ctypes_fnptr_reason,
-                        help: Some(fluent::lint_improper_ctypes_fnptr_help),
-                    };
-                }
-
-                let sig = tcx.instantiate_bound_regions_with_erased(sig);
-                for arg in sig.inputs() {
-                    match self.check_type_for_ffi(acc, *arg) {
-                        FfiSafe => {}
-                        r => return r,
-                    }
-                }
-
-                let ret_ty = sig.output();
-                if ret_ty.is_unit() {
-                    return FfiSafe;
-                }
-
-                self.check_type_for_ffi(acc, ret_ty)
-            }
-
-            ty::Foreign(..) => FfiSafe,
-
-            // While opaque types are checked for earlier, if a projection in a struct field
-            // normalizes to an opaque type, then it will reach this branch.
-            ty::Alias(ty::Opaque, ..) => {
-                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
-            }
-
-            // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
-            //  so they are currently ignored for the purposes of this lint.
-            ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
-                if matches!(self.mode, CItemKind::Definition) =>
-            {
-                FfiSafe
-            }
-
-            ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
-
-            ty::Param(..)
-            | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
-            | ty::Infer(..)
-            | ty::Bound(..)
-            | ty::Error(_)
-            | ty::Closure(..)
-            | ty::CoroutineClosure(..)
-            | ty::Coroutine(..)
-            | ty::CoroutineWitness(..)
-            | ty::Placeholder(..)
-            | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
-        }
-    }
-
-    fn emit_ffi_unsafe_type_lint(
-        &mut self,
-        ty: Ty<'tcx>,
-        sp: Span,
-        note: DiagMessage,
-        help: Option<DiagMessage>,
-    ) {
-        let lint = match self.mode {
-            CItemKind::Declaration => IMPROPER_CTYPES,
-            CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
-        };
-        let desc = match self.mode {
-            CItemKind::Declaration => "block",
-            CItemKind::Definition => "fn",
-        };
-        let span_note = if let ty::Adt(def, _) = ty.kind()
-            && let Some(sp) = self.cx.tcx.hir_span_if_local(def.did())
-        {
-            Some(sp)
-        } else {
-            None
-        };
-        self.cx.emit_span_lint(
-            lint,
-            sp,
-            ImproperCTypes { ty, desc, label: sp, help, note, span_note },
-        );
-    }
-
-    fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
-        struct ProhibitOpaqueTypes;
-        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
-            type Result = ControlFlow<Ty<'tcx>>;
-
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-                if !ty.has_opaque_types() {
-                    return ControlFlow::Continue(());
-                }
-
-                if let ty::Alias(ty::Opaque, ..) = ty.kind() {
-                    ControlFlow::Break(ty)
-                } else {
-                    ty.super_visit_with(self)
-                }
-            }
-        }
-
-        if let Some(ty) = self
-            .cx
-            .tcx
-            .try_normalize_erasing_regions(self.cx.typing_env(), ty)
-            .unwrap_or(ty)
-            .visit_with(&mut ProhibitOpaqueTypes)
-            .break_value()
-        {
-            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
-            true
-        } else {
-            false
-        }
-    }
-
-    fn check_type_for_ffi_and_report_errors(
-        &mut self,
-        sp: Span,
-        ty: Ty<'tcx>,
-        is_static: bool,
-        is_return_type: bool,
-    ) {
-        if self.check_for_opaque_ty(sp, ty) {
-            // We've already emitted an error due to an opaque type.
-            return;
-        }
-
-        let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
-
-        // C doesn't really support passing arrays by value - the only way to pass an array by value
-        // is through a struct. So, first test that the top level isn't an array, and then
-        // recursively check the types inside.
-        if !is_static && self.check_for_array_ty(sp, ty) {
-            return;
-        }
-
-        // Don't report FFI errors for unit return types. This check exists here, and not in
-        // the caller (where it would make more sense) so that normalization has definitely
-        // happened.
-        if is_return_type && ty.is_unit() {
-            return;
-        }
-
-        let mut acc = CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty };
-        match self.check_type_for_ffi(&mut acc, ty) {
-            FfiResult::FfiSafe => {}
-            FfiResult::FfiPhantom(ty) => {
-                self.emit_ffi_unsafe_type_lint(
-                    ty,
-                    sp,
-                    fluent::lint_improper_ctypes_only_phantomdata,
-                    None,
-                );
-            }
-            FfiResult::FfiUnsafe { ty, reason, help } => {
-                self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
-            }
-        }
-    }
-
-    /// Check if a function's argument types and result type are "ffi-safe".
-    ///
-    /// For a external ABI function, argument types and the result type are walked to find fn-ptr
-    /// types that have external ABIs, as these still need checked.
-    fn check_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) {
-        let sig = self.cx.tcx.fn_sig(def_id).instantiate_identity();
-        let sig = self.cx.tcx.instantiate_bound_regions_with_erased(sig);
-
-        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
-            for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(input_hir, *input_ty) {
-                self.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, false);
-            }
-        }
-
-        if let hir::FnRetTy::Return(ret_hir) = decl.output {
-            for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(ret_hir, sig.output()) {
-                self.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, true);
-            }
-        }
-    }
-
-    /// Check if a function's argument types and result type are "ffi-safe".
-    fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) {
-        let sig = self.cx.tcx.fn_sig(def_id).instantiate_identity();
-        let sig = self.cx.tcx.instantiate_bound_regions_with_erased(sig);
-
-        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
-            self.check_type_for_ffi_and_report_errors(input_hir.span, *input_ty, false, false);
-        }
-
-        if let hir::FnRetTy::Return(ret_hir) = decl.output {
-            self.check_type_for_ffi_and_report_errors(ret_hir.span, sig.output(), false, true);
-        }
-    }
-
-    fn check_foreign_static(&mut self, id: hir::OwnerId, span: Span) {
-        let ty = self.cx.tcx.type_of(id).instantiate_identity();
-        self.check_type_for_ffi_and_report_errors(span, ty, true, false);
-    }
-
-    /// Find any fn-ptr types with external ABIs in `ty`.
-    ///
-    /// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
-    fn find_fn_ptr_ty_with_external_abi(
-        &self,
-        hir_ty: &hir::Ty<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Vec<(Ty<'tcx>, Span)> {
-        struct FnPtrFinder<'tcx> {
-            spans: Vec<Span>,
-            tys: Vec<Ty<'tcx>>,
-        }
-
-        impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
-            fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
-                debug!(?ty);
-                if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
-                    && !abi.is_rustic_abi()
-                {
-                    self.spans.push(ty.span);
-                }
-
-                hir::intravisit::walk_ty(self, ty)
-            }
-        }
-
-        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
-            type Result = ();
-
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-                if let ty::FnPtr(_, hdr) = ty.kind()
-                    && !hdr.abi.is_rustic_abi()
-                {
-                    self.tys.push(ty);
-                }
-
-                ty.super_visit_with(self)
-            }
-        }
-
-        let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() };
-        ty.visit_with(&mut visitor);
-        visitor.visit_ty_unambig(hir_ty);
-
-        iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
-    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
-        let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration };
-        let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
-
-        match it.kind {
-            hir::ForeignItemKind::Fn(sig, _, _) => {
-                if abi.is_rustic_abi() {
-                    vis.check_fn(it.owner_id.def_id, sig.decl)
-                } else {
-                    vis.check_foreign_fn(it.owner_id.def_id, sig.decl);
-                }
-            }
-            hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
-                vis.check_foreign_static(it.owner_id, ty.span);
-            }
-            hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
-        }
-    }
-}
-
-impl ImproperCTypesDefinitions {
-    fn check_ty_maybe_containing_foreign_fnptr<'tcx>(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        hir_ty: &'tcx hir::Ty<'_>,
-        ty: Ty<'tcx>,
-    ) {
-        let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
-        for (fn_ptr_ty, span) in vis.find_fn_ptr_ty_with_external_abi(hir_ty, ty) {
-            vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
-        }
-    }
-
-    fn check_arg_for_power_alignment<'tcx>(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> bool {
-        assert!(cx.tcx.sess.target.os == "aix");
-        // Structs (under repr(C)) follow the power alignment rule if:
-        //   - the first field of the struct is a floating-point type that
-        //     is greater than 4-bytes, or
-        //   - the first field of the struct is an aggregate whose
-        //     recursively first field is a floating-point type greater than
-        //     4 bytes.
-        if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 {
-            return true;
-        } else if let Adt(adt_def, _) = ty.kind()
-            && adt_def.is_struct()
-            && adt_def.repr().c()
-            && !adt_def.repr().packed()
-            && adt_def.repr().align.is_none()
-        {
-            let struct_variant = adt_def.variant(VariantIdx::ZERO);
-            // Within a nested struct, all fields are examined to correctly
-            // report if any fields after the nested struct within the
-            // original struct are misaligned.
-            for struct_field in &struct_variant.fields {
-                let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity();
-                if self.check_arg_for_power_alignment(cx, field_ty) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    fn check_struct_for_power_alignment<'tcx>(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        item: &'tcx hir::Item<'tcx>,
-    ) {
-        let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id());
-        // repr(C) structs also with packed or aligned representation
-        // should be ignored.
-        if adt_def.repr().c()
-            && !adt_def.repr().packed()
-            && adt_def.repr().align.is_none()
-            && cx.tcx.sess.target.os == "aix"
-            && !adt_def.all_fields().next().is_none()
-        {
-            let struct_variant_data = item.expect_struct().2;
-            for field_def in struct_variant_data.fields().iter().skip(1) {
-                // Struct fields (after the first field) are checked for the
-                // power alignment rule, as fields after the first are likely
-                // to be the fields that are misaligned.
-                let def_id = field_def.def_id;
-                let ty = cx.tcx.type_of(def_id).instantiate_identity();
-                if self.check_arg_for_power_alignment(cx, ty) {
-                    cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
-                }
-            }
-        }
-    }
-}
-
-/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
-/// `extern "C" { }` blocks):
-///
-/// - `extern "<abi>" fn` definitions are checked in the same way as the
-///   `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
-/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
-///   checked for extern fn-ptrs with external ABIs.
-impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        match item.kind {
-            hir::ItemKind::Static(_, _, ty, _)
-            | hir::ItemKind::Const(_, _, ty, _)
-            | hir::ItemKind::TyAlias(_, _, ty) => {
-                self.check_ty_maybe_containing_foreign_fnptr(
-                    cx,
-                    ty,
-                    cx.tcx.type_of(item.owner_id).instantiate_identity(),
-                );
-            }
-            // See `check_fn`..
-            hir::ItemKind::Fn { .. } => {}
-            // Structs are checked based on if they follow the power alignment
-            // rule (under repr(C)).
-            hir::ItemKind::Struct(..) => {
-                self.check_struct_for_power_alignment(cx, item);
-            }
-            // See `check_field_def`..
-            hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
-            // Doesn't define something that can contain a external type to be checked.
-            hir::ItemKind::Impl(..)
-            | hir::ItemKind::TraitAlias(..)
-            | hir::ItemKind::Trait(..)
-            | hir::ItemKind::GlobalAsm { .. }
-            | hir::ItemKind::ForeignMod { .. }
-            | hir::ItemKind::Mod(..)
-            | hir::ItemKind::Macro(..)
-            | hir::ItemKind::Use(..)
-            | hir::ItemKind::ExternCrate(..) => {}
-        }
-    }
-
-    fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
-        self.check_ty_maybe_containing_foreign_fnptr(
-            cx,
-            field.ty,
-            cx.tcx.type_of(field.def_id).instantiate_identity(),
-        );
-    }
-
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        kind: hir::intravisit::FnKind<'tcx>,
-        decl: &'tcx hir::FnDecl<'_>,
-        _: &'tcx hir::Body<'_>,
-        _: Span,
-        id: LocalDefId,
-    ) {
-        use hir::intravisit::FnKind;
-
-        let abi = match kind {
-            FnKind::ItemFn(_, _, header, ..) => header.abi,
-            FnKind::Method(_, sig, ..) => sig.header.abi,
-            _ => return,
-        };
-
-        let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
-        if abi.is_rustic_abi() {
-            vis.check_fn(id, decl);
-        } else {
-            vis.check_foreign_fn(id, decl);
-        }
-    }
-}
-
 declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
 
 impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs
index 13afa540afc..7ca57b0094e 100644
--- a/compiler/rustc_lint/src/types/improper_ctypes.rs
+++ b/compiler/rustc_lint/src/types/improper_ctypes.rs
@@ -1,10 +1,141 @@
+use std::iter;
 use std::ops::ControlFlow;
 
+use bitflags::bitflags;
+use rustc_abi::VariantIdx;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::DiagMessage;
 use rustc_hir::def::CtorKind;
-use rustc_middle::ty;
+use rustc_hir::intravisit::VisitorExt;
+use rustc_hir::{self as hir, AmbigArg};
+use rustc_middle::bug;
+use rustc_middle::ty::{
+    self, Adt, AdtDef, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt,
+};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::{Span, sym};
+use tracing::debug;
 
-use crate::fluent_generated as fluent;
+use super::repr_nullable_ptr;
+use crate::lints::{ImproperCTypes, UsesPowerAlignment};
+use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
+
+declare_lint! {
+    /// The `improper_ctypes` lint detects incorrect use of types in foreign
+    /// modules.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe extern "C" {
+    ///     static STATIC: String;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler has several checks to verify that types used in `extern`
+    /// blocks are safe and follow certain rules to ensure proper
+    /// compatibility with the foreign interfaces. This lint is issued when it
+    /// detects a probable mistake in a definition. The lint usually should
+    /// provide a description of the issue, along with possibly a hint on how
+    /// to resolve it.
+    IMPROPER_CTYPES,
+    Warn,
+    "proper use of libc types in foreign modules"
+}
+
+declare_lint! {
+    /// The `improper_ctypes_definitions` lint detects incorrect use of
+    /// [`extern` function] definitions.
+    ///
+    /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// pub extern "C" fn str_type(p: &str) { }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// There are many parameter and return types that may be specified in an
+    /// `extern` function that are not compatible with the given ABI. This
+    /// lint is an alert that these types should not be used. The lint usually
+    /// should provide a description of the issue, along with possibly a hint
+    /// on how to resolve it.
+    IMPROPER_CTYPES_DEFINITIONS,
+    Warn,
+    "proper use of libc types in foreign item definitions"
+}
+
+declare_lint! {
+    /// The `uses_power_alignment` lint detects specific `repr(C)`
+    /// aggregates on AIX.
+    /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
+    /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
+    /// which can also be set for XLC by `#pragma align(power)` or
+    /// `-qalign=power`. Aggregates with a floating-point type as the
+    /// recursively first field (as in "at offset 0") modify the layout of
+    /// *subsequent* fields of the associated structs to use an alignment value
+    /// where the floating-point type is aligned on a 4-byte boundary.
+    ///
+    /// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
+    /// would be unsound to do in a `repr(C)` type without all the restrictions that come with
+    /// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
+    /// expense of incompatibility with C code.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
+    /// #[repr(C)]
+    /// pub struct Floats {
+    ///     a: f64,
+    ///     b: u8,
+    ///     c: f64,
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    ///  --> <source>:5:3
+    ///   |
+    /// 5 |   c: f64,
+    ///   |   ^^^^^^
+    ///   |
+    ///   = note: `#[warn(uses_power_alignment)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// The power alignment rule specifies that the above struct has the
+    /// following alignment:
+    ///  - offset_of!(Floats, a) == 0
+    ///  - offset_of!(Floats, b) == 8
+    ///  - offset_of!(Floats, c) == 12
+    ///
+    /// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
+    /// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
+    /// Thus, a warning is produced for the above struct.
+    USES_POWER_ALIGNMENT,
+    Warn,
+    "Structs do not follow the power alignment rule under repr(C)"
+}
+
+declare_lint_pass!(ImproperCTypesLint => [
+    IMPROPER_CTYPES,
+    IMPROPER_CTYPES_DEFINITIONS,
+    USES_POWER_ALIGNMENT
+]);
 
 /// Check a variant of a non-exhaustive enum for improper ctypes
 ///
@@ -41,3 +172,884 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
     // CtorKind::Const means a "unit" ctor
     !matches!(variant.ctor_kind(), Some(CtorKind::Const))
 }
+
+/// Per-struct-field function that checks if a struct definition follows
+/// the Power alignment Rule (see the `check_struct_for_power_alignment` function).
+fn check_arg_for_power_alignment<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    let tcx = cx.tcx;
+    assert!(tcx.sess.target.os == "aix");
+    // Structs (under repr(C)) follow the power alignment rule if:
+    //   - the first field of the struct is a floating-point type that
+    //     is greater than 4-bytes, or
+    //   - the first field of the struct is an aggregate whose
+    //     recursively first field is a floating-point type greater than
+    //     4 bytes.
+    if ty.is_floating_point() && ty.primitive_size(tcx).bytes() > 4 {
+        return true;
+    } else if let Adt(adt_def, _) = ty.kind()
+        && adt_def.is_struct()
+        && adt_def.repr().c()
+        && !adt_def.repr().packed()
+        && adt_def.repr().align.is_none()
+    {
+        let struct_variant = adt_def.variant(VariantIdx::ZERO);
+        // Within a nested struct, all fields are examined to correctly
+        // report if any fields after the nested struct within the
+        // original struct are misaligned.
+        for struct_field in &struct_variant.fields {
+            let field_ty = tcx.type_of(struct_field.did).instantiate_identity();
+            if check_arg_for_power_alignment(cx, field_ty) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/// Check a struct definition for respect of the Power alignment Rule (as in PowerPC),
+/// which should be respected in the "aix" target OS.
+/// To do so, we must follow one of the two following conditions:
+/// - The first field of the struct must be floating-point type that
+///    is greater than 4-bytes.
+///  - The first field of the struct must be an aggregate whose
+///    recursively first field is a floating-point type greater than
+///    4 bytes.
+fn check_struct_for_power_alignment<'tcx>(
+    cx: &LateContext<'tcx>,
+    item: &'tcx hir::Item<'tcx>,
+    adt_def: AdtDef<'tcx>,
+) {
+    let tcx = cx.tcx;
+    // repr(C) structs also with packed or aligned representation
+    // should be ignored.
+    if adt_def.repr().c()
+        && !adt_def.repr().packed()
+        && adt_def.repr().align.is_none()
+        && tcx.sess.target.os == "aix"
+        && !adt_def.all_fields().next().is_none()
+    {
+        let struct_variant_data = item.expect_struct().2;
+        for field_def in struct_variant_data.fields().iter().skip(1) {
+            // Struct fields (after the first field) are checked for the
+            // power alignment rule, as fields after the first are likely
+            // to be the fields that are misaligned.
+            let def_id = field_def.def_id;
+            let ty = tcx.type_of(def_id).instantiate_identity();
+            if check_arg_for_power_alignment(cx, ty) {
+                cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
+            }
+        }
+    }
+}
+
+#[derive(Clone, Copy)]
+enum CItemKind {
+    Declaration,
+    Definition,
+}
+
+enum FfiResult<'tcx> {
+    FfiSafe,
+    FfiPhantom(Ty<'tcx>),
+    FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
+}
+
+/// The result when a type has been checked but perhaps not completely. `None` indicates that
+/// FFI safety/unsafety has not yet been determined, `Some(res)` indicates that the safety/unsafety
+/// in the `FfiResult` is final.
+type PartialFfiResult<'tcx> = Option<FfiResult<'tcx>>;
+
+bitflags! {
+    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+    struct VisitorState: u8 {
+        /// For use in (externally-linked) static variables.
+        const STATIC = 0b000001;
+        /// For use in functions in general.
+        const FUNC = 0b000010;
+        /// For variables in function returns (implicitly: not for static variables).
+        const FN_RETURN = 0b000100;
+        /// For variables in functions/variables which are defined in rust.
+        const DEFINED = 0b001000;
+        /// For times where we are only defining the type of something
+        /// (struct/enum/union definitions, FnPtrs).
+        const THEORETICAL = 0b010000;
+    }
+}
+
+impl VisitorState {
+    // The values that can be set.
+    const STATIC_TY: Self = Self::STATIC;
+    const ARGUMENT_TY_IN_DEFINITION: Self =
+        Self::from_bits(Self::FUNC.bits() | Self::DEFINED.bits()).unwrap();
+    const RETURN_TY_IN_DEFINITION: Self =
+        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits() | Self::DEFINED.bits()).unwrap();
+    const ARGUMENT_TY_IN_DECLARATION: Self = Self::FUNC;
+    const RETURN_TY_IN_DECLARATION: Self =
+        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits()).unwrap();
+    const ARGUMENT_TY_IN_FNPTR: Self =
+        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits()).unwrap();
+    const RETURN_TY_IN_FNPTR: Self =
+        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits() | Self::FN_RETURN.bits())
+            .unwrap();
+
+    /// Get the proper visitor state for a given function's arguments.
+    fn argument_from_fnmode(fn_mode: CItemKind) -> Self {
+        match fn_mode {
+            CItemKind::Definition => VisitorState::ARGUMENT_TY_IN_DEFINITION,
+            CItemKind::Declaration => VisitorState::ARGUMENT_TY_IN_DECLARATION,
+        }
+    }
+
+    /// Get the proper visitor state for a given function's return type.
+    fn return_from_fnmode(fn_mode: CItemKind) -> Self {
+        match fn_mode {
+            CItemKind::Definition => VisitorState::RETURN_TY_IN_DEFINITION,
+            CItemKind::Declaration => VisitorState::RETURN_TY_IN_DECLARATION,
+        }
+    }
+
+    /// Whether the type is used in a function.
+    fn is_in_function(self) -> bool {
+        let ret = self.contains(Self::FUNC);
+        if ret {
+            debug_assert!(!self.contains(Self::STATIC));
+        }
+        ret
+    }
+    /// Whether the type is used (directly or not) in a function, in return position.
+    fn is_in_function_return(self) -> bool {
+        let ret = self.contains(Self::FN_RETURN);
+        if ret {
+            debug_assert!(self.is_in_function());
+        }
+        ret
+    }
+    /// Whether the type is used (directly or not) in a defined function.
+    /// In other words, whether or not we allow non-FFI-safe types behind a C pointer,
+    /// to be treated as an opaque type on the other side of the FFI boundary.
+    fn is_in_defined_function(self) -> bool {
+        self.contains(Self::DEFINED) && self.is_in_function()
+    }
+
+    /// Whether the type is used (directly or not) in a function pointer type.
+    /// Here, we also allow non-FFI-safe types behind a C pointer,
+    /// to be treated as an opaque type on the other side of the FFI boundary.
+    fn is_in_fnptr(self) -> bool {
+        self.contains(Self::THEORETICAL) && self.is_in_function()
+    }
+
+    /// Whether we can expect type parameters and co in a given type.
+    fn can_expect_ty_params(self) -> bool {
+        // rust-defined functions, as well as FnPtrs
+        self.contains(Self::THEORETICAL) || self.is_in_defined_function()
+    }
+}
+
+/// Visitor used to recursively traverse MIR types and evaluate FFI-safety.
+/// It uses ``check_*`` methods as entrypoints to be called elsewhere,
+/// and ``visit_*`` methods to recurse.
+struct ImproperCTypesVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    /// To prevent problems with recursive types,
+    /// add a types-in-check cache.
+    cache: FxHashSet<Ty<'tcx>>,
+    /// The original type being checked, before we recursed
+    /// to any other types it contains.
+    base_ty: Ty<'tcx>,
+    base_fn_mode: CItemKind,
+}
+
+impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>, base_ty: Ty<'tcx>, base_fn_mode: CItemKind) -> Self {
+        Self { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
+    }
+
+    /// Checks if the given field's type is "ffi-safe".
+    fn check_field_type_for_ffi(
+        &mut self,
+        state: VisitorState,
+        field: &ty::FieldDef,
+        args: GenericArgsRef<'tcx>,
+    ) -> FfiResult<'tcx> {
+        let field_ty = field.ty(self.cx.tcx, args);
+        let field_ty = self
+            .cx
+            .tcx
+            .try_normalize_erasing_regions(self.cx.typing_env(), field_ty)
+            .unwrap_or(field_ty);
+        self.visit_type(state, field_ty)
+    }
+
+    /// Checks if the given `VariantDef`'s field types are "ffi-safe".
+    fn check_variant_for_ffi(
+        &mut self,
+        state: VisitorState,
+        ty: Ty<'tcx>,
+        def: ty::AdtDef<'tcx>,
+        variant: &ty::VariantDef,
+        args: GenericArgsRef<'tcx>,
+    ) -> FfiResult<'tcx> {
+        use FfiResult::*;
+        let transparent_with_all_zst_fields = if def.repr().transparent() {
+            if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) {
+                // Transparent newtypes have at most one non-ZST field which needs to be checked..
+                match self.check_field_type_for_ffi(state, field, args) {
+                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
+                    r => return r,
+                }
+
+                false
+            } else {
+                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
+                // `PhantomData`).
+                true
+            }
+        } else {
+            false
+        };
+
+        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
+        let mut all_phantom = !variant.fields.is_empty();
+        for field in &variant.fields {
+            all_phantom &= match self.check_field_type_for_ffi(state, field, args) {
+                FfiSafe => false,
+                // `()` fields are FFI-safe!
+                FfiUnsafe { ty, .. } if ty.is_unit() => false,
+                FfiPhantom(..) => true,
+                r @ FfiUnsafe { .. } => return r,
+            }
+        }
+
+        if all_phantom {
+            FfiPhantom(ty)
+        } else if transparent_with_all_zst_fields {
+            FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
+        } else {
+            FfiSafe
+        }
+    }
+
+    /// Checks if the given type is "ffi-safe" (has a stable, well-defined
+    /// representation which can be exported to C code).
+    fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
+        use FfiResult::*;
+
+        let tcx = self.cx.tcx;
+
+        // Protect against infinite recursion, for example
+        // `struct S(*mut S);`.
+        // FIXME: A recursion limit is necessary as well, for irregular
+        // recursive types.
+        if !self.cache.insert(ty) {
+            return FfiSafe;
+        }
+
+        match *ty.kind() {
+            ty::Adt(def, args) => {
+                if let Some(boxed) = ty.boxed_ty()
+                    && (
+                        // FIXME(ctypes): this logic is broken, but it still fits the current tests
+                        state.is_in_defined_function()
+                            || (state.is_in_fnptr()
+                                && matches!(self.base_fn_mode, CItemKind::Definition))
+                    )
+                {
+                    if boxed.is_sized(tcx, self.cx.typing_env()) {
+                        return FfiSafe;
+                    } else {
+                        return FfiUnsafe {
+                            ty,
+                            reason: fluent::lint_improper_ctypes_box,
+                            help: None,
+                        };
+                    }
+                }
+                if def.is_phantom_data() {
+                    return FfiPhantom(ty);
+                }
+                match def.adt_kind() {
+                    AdtKind::Struct | AdtKind::Union => {
+                        if let Some(sym::cstring_type | sym::cstr_type) =
+                            tcx.get_diagnostic_name(def.did())
+                            && !self.base_ty.is_mutable_ptr()
+                        {
+                            return FfiUnsafe {
+                                ty,
+                                reason: fluent::lint_improper_ctypes_cstr_reason,
+                                help: Some(fluent::lint_improper_ctypes_cstr_help),
+                            };
+                        }
+
+                        if !def.repr().c() && !def.repr().transparent() {
+                            return FfiUnsafe {
+                                ty,
+                                reason: if def.is_struct() {
+                                    fluent::lint_improper_ctypes_struct_layout_reason
+                                } else {
+                                    fluent::lint_improper_ctypes_union_layout_reason
+                                },
+                                help: if def.is_struct() {
+                                    Some(fluent::lint_improper_ctypes_struct_layout_help)
+                                } else {
+                                    Some(fluent::lint_improper_ctypes_union_layout_help)
+                                },
+                            };
+                        }
+
+                        if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
+                            return FfiUnsafe {
+                                ty,
+                                reason: if def.is_struct() {
+                                    fluent::lint_improper_ctypes_struct_non_exhaustive
+                                } else {
+                                    fluent::lint_improper_ctypes_union_non_exhaustive
+                                },
+                                help: None,
+                            };
+                        }
+
+                        if def.non_enum_variant().fields.is_empty() {
+                            return FfiUnsafe {
+                                ty,
+                                reason: if def.is_struct() {
+                                    fluent::lint_improper_ctypes_struct_fieldless_reason
+                                } else {
+                                    fluent::lint_improper_ctypes_union_fieldless_reason
+                                },
+                                help: if def.is_struct() {
+                                    Some(fluent::lint_improper_ctypes_struct_fieldless_help)
+                                } else {
+                                    Some(fluent::lint_improper_ctypes_union_fieldless_help)
+                                },
+                            };
+                        }
+
+                        self.check_variant_for_ffi(state, ty, def, def.non_enum_variant(), args)
+                    }
+                    AdtKind::Enum => {
+                        if def.variants().is_empty() {
+                            // Empty enums are okay... although sort of useless.
+                            return FfiSafe;
+                        }
+                        // Check for a repr() attribute to specify the size of the
+                        // discriminant.
+                        if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
+                        {
+                            // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
+                            if let Some(ty) =
+                                repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty)
+                            {
+                                return self.visit_type(state, ty);
+                            }
+
+                            return FfiUnsafe {
+                                ty,
+                                reason: fluent::lint_improper_ctypes_enum_repr_reason,
+                                help: Some(fluent::lint_improper_ctypes_enum_repr_help),
+                            };
+                        }
+
+                        let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
+                        // Check the contained variants.
+                        let ret = def.variants().iter().try_for_each(|variant| {
+                            check_non_exhaustive_variant(non_exhaustive, variant)
+                                .map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
+
+                            match self.check_variant_for_ffi(state, ty, def, variant, args) {
+                                FfiSafe => ControlFlow::Continue(()),
+                                r => ControlFlow::Break(r),
+                            }
+                        });
+                        if let ControlFlow::Break(result) = ret {
+                            return result;
+                        }
+
+                        FfiSafe
+                    }
+                }
+            }
+
+            ty::Char => FfiUnsafe {
+                ty,
+                reason: fluent::lint_improper_ctypes_char_reason,
+                help: Some(fluent::lint_improper_ctypes_char_help),
+            },
+
+            // It's just extra invariants on the type that you need to uphold,
+            // but only the base type is relevant for being representable in FFI.
+            ty::Pat(base, ..) => self.visit_type(state, base),
+
+            // Primitive types with a stable representation.
+            ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
+
+            ty::Slice(_) => FfiUnsafe {
+                ty,
+                reason: fluent::lint_improper_ctypes_slice_reason,
+                help: Some(fluent::lint_improper_ctypes_slice_help),
+            },
+
+            ty::Dynamic(..) => {
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
+            }
+
+            ty::Str => FfiUnsafe {
+                ty,
+                reason: fluent::lint_improper_ctypes_str_reason,
+                help: Some(fluent::lint_improper_ctypes_str_help),
+            },
+
+            ty::Tuple(..) => FfiUnsafe {
+                ty,
+                reason: fluent::lint_improper_ctypes_tuple_reason,
+                help: Some(fluent::lint_improper_ctypes_tuple_help),
+            },
+
+            ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
+                if {
+                    (state.is_in_defined_function() || state.is_in_fnptr())
+                        && ty.is_sized(self.cx.tcx, self.cx.typing_env())
+                } =>
+            {
+                FfiSafe
+            }
+
+            ty::RawPtr(ty, _)
+                if match ty.kind() {
+                    ty::Tuple(tuple) => tuple.is_empty(),
+                    _ => false,
+                } =>
+            {
+                FfiSafe
+            }
+
+            ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.visit_type(state, ty),
+
+            ty::Array(inner_ty, _) => self.visit_type(state, inner_ty),
+
+            ty::FnPtr(sig_tys, hdr) => {
+                let sig = sig_tys.with(hdr);
+                if sig.abi().is_rustic_abi() {
+                    return FfiUnsafe {
+                        ty,
+                        reason: fluent::lint_improper_ctypes_fnptr_reason,
+                        help: Some(fluent::lint_improper_ctypes_fnptr_help),
+                    };
+                }
+
+                let sig = tcx.instantiate_bound_regions_with_erased(sig);
+                for arg in sig.inputs() {
+                    match self.visit_type(VisitorState::ARGUMENT_TY_IN_FNPTR, *arg) {
+                        FfiSafe => {}
+                        r => return r,
+                    }
+                }
+
+                let ret_ty = sig.output();
+                if ret_ty.is_unit() {
+                    return FfiSafe;
+                }
+
+                self.visit_type(VisitorState::RETURN_TY_IN_FNPTR, ret_ty)
+            }
+
+            ty::Foreign(..) => FfiSafe,
+
+            // While opaque types are checked for earlier, if a projection in a struct field
+            // normalizes to an opaque type, then it will reach this branch.
+            ty::Alias(ty::Opaque, ..) => {
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
+            }
+
+            // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
+            //  so they are currently ignored for the purposes of this lint.
+            ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
+                if state.can_expect_ty_params() =>
+            {
+                FfiSafe
+            }
+
+            ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+
+            ty::Param(..)
+            | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
+            | ty::Infer(..)
+            | ty::Bound(..)
+            | ty::Error(_)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineWitness(..)
+            | ty::Placeholder(..)
+            | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
+        }
+    }
+
+    fn visit_for_opaque_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
+        struct ProhibitOpaqueTypes;
+        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
+            type Result = ControlFlow<Ty<'tcx>>;
+
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+                if !ty.has_opaque_types() {
+                    return ControlFlow::Continue(());
+                }
+
+                if let ty::Alias(ty::Opaque, ..) = ty.kind() {
+                    ControlFlow::Break(ty)
+                } else {
+                    ty.super_visit_with(self)
+                }
+            }
+        }
+
+        if let Some(ty) = self
+            .cx
+            .tcx
+            .try_normalize_erasing_regions(self.cx.typing_env(), ty)
+            .unwrap_or(ty)
+            .visit_with(&mut ProhibitOpaqueTypes)
+            .break_value()
+        {
+            Some(FfiResult::FfiUnsafe {
+                ty,
+                reason: fluent::lint_improper_ctypes_opaque,
+                help: None,
+            })
+        } else {
+            None
+        }
+    }
+
+    /// Check if the type is array and emit an unsafe type lint.
+    fn check_for_array_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
+        if let ty::Array(..) = ty.kind() {
+            Some(FfiResult::FfiUnsafe {
+                ty,
+                reason: fluent::lint_improper_ctypes_array_reason,
+                help: Some(fluent::lint_improper_ctypes_array_help),
+            })
+        } else {
+            None
+        }
+    }
+
+    /// Determine the FFI-safety of a single (MIR) type, given the context of how it is used.
+    fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
+        if let Some(res) = self.visit_for_opaque_ty(ty) {
+            return res;
+        }
+
+        let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
+
+        // C doesn't really support passing arrays by value - the only way to pass an array by value
+        // is through a struct. So, first test that the top level isn't an array, and then
+        // recursively check the types inside.
+        if state.is_in_function() {
+            if let Some(res) = self.check_for_array_ty(ty) {
+                return res;
+            }
+        }
+
+        // Don't report FFI errors for unit return types. This check exists here, and not in
+        // the caller (where it would make more sense) so that normalization has definitely
+        // happened.
+        if state.is_in_function_return() && ty.is_unit() {
+            return FfiResult::FfiSafe;
+        }
+
+        self.visit_type(state, ty)
+    }
+}
+
+impl<'tcx> ImproperCTypesLint {
+    /// Find any fn-ptr types with external ABIs in `ty`, and FFI-checks them.
+    /// For example, `Option<extern "C" fn()>` FFI-checks `extern "C" fn()`.
+    fn check_type_for_external_abi_fnptr(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        state: VisitorState,
+        hir_ty: &hir::Ty<'tcx>,
+        ty: Ty<'tcx>,
+        fn_mode: CItemKind,
+    ) {
+        struct FnPtrFinder<'tcx> {
+            spans: Vec<Span>,
+            tys: Vec<Ty<'tcx>>,
+        }
+
+        impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
+            fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
+                debug!(?ty);
+                if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
+                    && !abi.is_rustic_abi()
+                {
+                    self.spans.push(ty.span);
+                }
+
+                hir::intravisit::walk_ty(self, ty)
+            }
+        }
+
+        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
+            type Result = ();
+
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+                if let ty::FnPtr(_, hdr) = ty.kind()
+                    && !hdr.abi.is_rustic_abi()
+                {
+                    self.tys.push(ty);
+                }
+
+                ty.super_visit_with(self)
+            }
+        }
+
+        let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() };
+        ty.visit_with(&mut visitor);
+        visitor.visit_ty_unambig(hir_ty);
+
+        let all_types = iter::zip(visitor.tys.drain(..), visitor.spans.drain(..));
+        for (fn_ptr_ty, span) in all_types {
+            let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode);
+            // FIXME(ctypes): make a check_for_fnptr
+            let ffi_res = visitor.check_type(state, fn_ptr_ty);
+
+            self.process_ffi_result(cx, span, ffi_res, fn_mode);
+        }
+    }
+
+    /// Regardless of a function's need to be "ffi-safe", look for fn-ptr argument/return types
+    /// that need to be checked for ffi-safety.
+    fn check_fn_for_external_abi_fnptr(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        fn_mode: CItemKind,
+        def_id: LocalDefId,
+        decl: &'tcx hir::FnDecl<'_>,
+    ) {
+        let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
+        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
+
+        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
+            let state = VisitorState::argument_from_fnmode(fn_mode);
+            self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode);
+        }
+
+        if let hir::FnRetTy::Return(ret_hir) = decl.output {
+            let state = VisitorState::return_from_fnmode(fn_mode);
+            self.check_type_for_external_abi_fnptr(cx, state, ret_hir, sig.output(), fn_mode);
+        }
+    }
+
+    /// For a local definition of a #[repr(C)] struct/enum/union, check that it is indeed FFI-safe.
+    fn check_reprc_adt(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        item: &'tcx hir::Item<'tcx>,
+        adt_def: AdtDef<'tcx>,
+    ) {
+        debug_assert!(
+            adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
+        );
+
+        // FIXME(ctypes): this following call is awkward.
+        // is there a way to perform its logic in MIR space rather than HIR space?
+        // (so that its logic can be absorbed into visitor.visit_struct_or_union)
+        check_struct_for_power_alignment(cx, item, adt_def);
+    }
+
+    fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
+        let ty = cx.tcx.type_of(id).instantiate_identity();
+        let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
+        let ffi_res = visitor.check_type(VisitorState::STATIC_TY, ty);
+        self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration);
+    }
+
+    /// Check if a function's argument types and result type are "ffi-safe".
+    fn check_foreign_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        fn_mode: CItemKind,
+        def_id: LocalDefId,
+        decl: &'tcx hir::FnDecl<'_>,
+    ) {
+        let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
+        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
+
+        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
+            let state = VisitorState::argument_from_fnmode(fn_mode);
+            let mut visitor = ImproperCTypesVisitor::new(cx, *input_ty, fn_mode);
+            let ffi_res = visitor.check_type(state, *input_ty);
+            self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode);
+        }
+
+        if let hir::FnRetTy::Return(ret_hir) = decl.output {
+            let state = VisitorState::return_from_fnmode(fn_mode);
+            let mut visitor = ImproperCTypesVisitor::new(cx, sig.output(), fn_mode);
+            let ffi_res = visitor.check_type(state, sig.output());
+            self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode);
+        }
+    }
+
+    fn process_ffi_result(
+        &self,
+        cx: &LateContext<'tcx>,
+        sp: Span,
+        res: FfiResult<'tcx>,
+        fn_mode: CItemKind,
+    ) {
+        match res {
+            FfiResult::FfiSafe => {}
+            FfiResult::FfiPhantom(ty) => {
+                self.emit_ffi_unsafe_type_lint(
+                    cx,
+                    ty,
+                    sp,
+                    fluent::lint_improper_ctypes_only_phantomdata,
+                    None,
+                    fn_mode,
+                );
+            }
+            FfiResult::FfiUnsafe { ty, reason, help } => {
+                self.emit_ffi_unsafe_type_lint(cx, ty, sp, reason, help, fn_mode);
+            }
+        }
+    }
+
+    fn emit_ffi_unsafe_type_lint(
+        &self,
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+        sp: Span,
+        note: DiagMessage,
+        help: Option<DiagMessage>,
+        fn_mode: CItemKind,
+    ) {
+        let lint = match fn_mode {
+            CItemKind::Declaration => IMPROPER_CTYPES,
+            CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
+        };
+        let desc = match fn_mode {
+            CItemKind::Declaration => "block",
+            CItemKind::Definition => "fn",
+        };
+        let span_note = if let ty::Adt(def, _) = ty.kind()
+            && let Some(sp) = cx.tcx.hir_span_if_local(def.did())
+        {
+            Some(sp)
+        } else {
+            None
+        };
+        cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, help, note, span_note });
+    }
+}
+
+/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
+/// `extern "C" { }` blocks):
+///
+/// - `extern "<abi>" fn` definitions are checked in the same way as the
+///   `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
+/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
+///   checked for extern fn-ptrs with external ABIs.
+impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
+    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
+        let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
+
+        match it.kind {
+            hir::ForeignItemKind::Fn(sig, _, _) => {
+                // fnptrs are a special case, they always need to be treated as
+                // "the element rendered unsafe" because their unsafety doesn't affect
+                // their surroundings, and their type is often declared inline
+                if !abi.is_rustic_abi() {
+                    self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
+                } else {
+                    self.check_fn_for_external_abi_fnptr(
+                        cx,
+                        CItemKind::Declaration,
+                        it.owner_id.def_id,
+                        sig.decl,
+                    );
+                }
+            }
+            hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
+                self.check_foreign_static(cx, it.owner_id, ty.span);
+            }
+            hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
+        }
+    }
+
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+        match item.kind {
+            hir::ItemKind::Static(_, _, ty, _)
+            | hir::ItemKind::Const(_, _, ty, _)
+            | hir::ItemKind::TyAlias(_, _, ty) => {
+                self.check_type_for_external_abi_fnptr(
+                    cx,
+                    VisitorState::STATIC_TY,
+                    ty,
+                    cx.tcx.type_of(item.owner_id).instantiate_identity(),
+                    CItemKind::Definition,
+                );
+            }
+            // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
+            hir::ItemKind::Fn { .. } => {}
+            hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {
+                // looking for extern FnPtr:s is delegated to `check_field_def`.
+                let adt_def: AdtDef<'tcx> = cx.tcx.adt_def(item.owner_id.to_def_id());
+
+                if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
+                {
+                    self.check_reprc_adt(cx, item, adt_def);
+                }
+            }
+
+            // Doesn't define something that can contain a external type to be checked.
+            hir::ItemKind::Impl(..)
+            | hir::ItemKind::TraitAlias(..)
+            | hir::ItemKind::Trait(..)
+            | hir::ItemKind::GlobalAsm { .. }
+            | hir::ItemKind::ForeignMod { .. }
+            | hir::ItemKind::Mod(..)
+            | hir::ItemKind::Macro(..)
+            | hir::ItemKind::Use(..)
+            | hir::ItemKind::ExternCrate(..) => {}
+        }
+    }
+
+    fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
+        self.check_type_for_external_abi_fnptr(
+            cx,
+            VisitorState::STATIC_TY,
+            field.ty,
+            cx.tcx.type_of(field.def_id).instantiate_identity(),
+            CItemKind::Definition,
+        );
+    }
+
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: hir::intravisit::FnKind<'tcx>,
+        decl: &'tcx hir::FnDecl<'_>,
+        _: &'tcx hir::Body<'_>,
+        _: Span,
+        id: LocalDefId,
+    ) {
+        use hir::intravisit::FnKind;
+
+        let abi = match kind {
+            FnKind::ItemFn(_, _, header, ..) => header.abi,
+            FnKind::Method(_, sig, ..) => sig.header.abi,
+            _ => return,
+        };
+
+        // fnptrs are a special case, they always need to be treated as
+        // "the element rendered unsafe" because their unsafety doesn't affect
+        // their surroundings, and their type is often declared inline
+        if !abi.is_rustic_abi() {
+            self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
+        } else {
+            self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
+        }
+    }
+}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index ce92263babd..b79075ac09b 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -5141,3 +5141,57 @@ declare_lint! {
     "detects tail calls of functions marked with `#[track_caller]`",
     @feature_gate = explicit_tail_calls;
 }
+declare_lint! {
+    /// The `inline_always_mismatching_target_features` lint will trigger when a
+    /// function with the `#[inline(always)]` and `#[target_feature(enable = "...")]`
+    /// attributes is called and cannot be inlined due to missing target features in the caller.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (fails on x86_64)
+    /// #[inline(always)]
+    /// #[target_feature(enable = "fp16")]
+    /// unsafe fn callee() {
+    ///     // operations using fp16 types
+    /// }
+    ///
+    /// // Caller does not enable the required target feature
+    /// fn caller() {
+    ///     unsafe { callee(); }
+    /// }
+    ///
+    /// fn main() {
+    ///     caller();
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: call to `#[inline(always)]`-annotated `callee` requires the same target features. Function will not have `alwaysinline` attribute applied
+    ///   --> $DIR/builtin.rs:5192:14
+    ///    |
+    /// 10 |     unsafe { callee(); }
+    ///    |              ^^^^^^^^
+    ///    |
+    /// note: `fp16` target feature enabled in `callee` here but missing from `caller`
+    ///   --> $DIR/builtin.rs:5185:1
+    ///    |
+    /// 3  | #[target_feature(enable = "fp16")]
+    ///    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    /// 4  | unsafe fn callee() {
+    ///    | ------------------
+    ///    = note: `#[warn(inline_always_mismatching_target_features)]` on by default
+    /// warning: 1 warning emitted
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Inlining a function with a target feature attribute into a caller that
+    /// lacks the corresponding target feature can lead to unsound behavior.
+    /// LLVM may select the wrong instructions or registers, or reorder
+    /// operations, potentially resulting in runtime errors.
+    pub INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
+    Warn,
+    r#"detects when a function annotated with `#[inline(always)]` and `#[target_feature(enable = "..")]` is inlined into a caller without the required target feature"#,
+}
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 804f46374d5..9d21d0d22e3 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -174,10 +174,10 @@ fn main() {
 
     // Prevent critical warnings when we're compiling from rust-lang/rust CI,
     // except on MSVC, as the compiler throws warnings that are only reported
-    // for this platform. See https://github.com/rust-lang/rust/pull/145031#issuecomment-3162677202
-    // FIXME(llvm22): It looks like the specific problem code has been removed
-    // in https://github.com/llvm/llvm-project/commit/e8fc808bf8e78a3c80d1f8e293a92677b92366dd,
-    // retry msvc once we bump our LLVM version.
+    // for this platform. See https://github.com/rust-lang/rust/pull/145031#issuecomment-3162677202.
+    // Moreover, LLVM generally guarantees warning-freedom only when building with Clang, as other
+    // compilers have too many false positives. This is typically the case for MSVC, which throws
+    // many false-positive warnings. We keep it excluded, for these reasons.
     if std::env::var_os("CI").is_some() && !target.contains("msvc") {
         cfg.warnings_into_errors(true);
     }
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index dd492325814..3bb1533c2fe 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1568,12 +1568,11 @@ extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data,
   return true;
 }
 
-extern "C" LLVMRustThinLTOBuffer *
-LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) {
+extern "C" LLVMRustThinLTOBuffer *LLVMRustThinLTOBufferCreate(LLVMModuleRef M,
+                                                              bool is_thin) {
   auto Ret = std::make_unique<LLVMRustThinLTOBuffer>();
   {
     auto OS = raw_string_ostream(Ret->data);
-    auto ThinLinkOS = raw_string_ostream(Ret->thin_link_data);
     {
       if (is_thin) {
         PassBuilder PB;
@@ -1587,11 +1586,7 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) {
         PB.registerLoopAnalyses(LAM);
         PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
         ModulePassManager MPM;
-        // We only pass ThinLinkOS to be filled in if we want the summary,
-        // because otherwise LLVM does extra work and may double-emit some
-        // errors or warnings.
-        MPM.addPass(
-            ThinLTOBitcodeWriterPass(OS, emit_summary ? &ThinLinkOS : nullptr));
+        MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr));
         MPM.run(*unwrap(M), MAM);
       } else {
         WriteBitcodeToFile(*unwrap(M), OS);
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
index c673d51a1d4..72f68d685cd 100644
--- a/compiler/rustc_log/Cargo.toml
+++ b/compiler/rustc_log/Cargo.toml
@@ -5,13 +5,12 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
-tracing = "0.1.28"
-tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635
+tracing = "0.1.41"
 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 tracing-tree = "0.3.1"
 # tidy-alphabetical-end
 
 [features]
 # tidy-alphabetical-start
-max_level_info = ['tracing/max_level_info']
+max_level_info = ['tracing/max_level_info', 'tracing/release_max_level_info']
 # tidy-alphabetical-end
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index df648bbd489..26475eec1c1 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -38,7 +38,7 @@ use std::fmt::{self, Display};
 use std::io::{self, IsTerminal};
 
 use tracing::dispatcher::SetGlobalDefaultError;
-use tracing_core::{Event, Subscriber};
+use tracing::{Event, Subscriber};
 use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
 use tracing_subscriber::fmt::FmtContext;
 use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields};
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 5d776ea581d..9e23da88f5e 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -412,7 +412,7 @@ impl CStore {
             match (&left_name_val, &right_name_val) {
                 (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
                     cmp::Ordering::Equal => {
-                        if l.0.tech_value != r.0.tech_value {
+                        if !l.1.consistent(&tcx.sess.opts, Some(&r.1)) {
                             report_diff(
                                 &l.0.prefix,
                                 &l.0.name,
@@ -424,20 +424,28 @@ impl CStore {
                         right_name_val = None;
                     }
                     cmp::Ordering::Greater => {
-                        report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                        if !r.1.consistent(&tcx.sess.opts, None) {
+                            report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                        }
                         right_name_val = None;
                     }
                     cmp::Ordering::Less => {
-                        report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                        if !l.1.consistent(&tcx.sess.opts, None) {
+                            report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                        }
                         left_name_val = None;
                     }
                 },
                 (Some(l), None) => {
-                    report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                    if !l.1.consistent(&tcx.sess.opts, None) {
+                        report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                    }
                     left_name_val = None;
                 }
                 (None, Some(r)) => {
-                    report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                    if !r.1.consistent(&tcx.sess.opts, None) {
+                        report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                    }
                     right_name_val = None;
                 }
                 (None, None) => break,
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 7520bc262c6..dad402ec696 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -72,7 +72,7 @@ pub enum TypeMismatchReason {
 #[help]
 pub(crate) struct RecursionLimitReached<'tcx> {
     pub ty: Ty<'tcx>,
-    pub suggested_limit: rustc_session::Limit,
+    pub suggested_limit: rustc_hir::limit::Limit,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 4fe4c2dadee..153605ee7f8 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -27,7 +27,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
 pub use rustc_type_ir as ir;
-pub use rustc_type_ir::CanonicalTyVarKind;
 use smallvec::SmallVec;
 
 use crate::mir::ConstraintCategory;
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 866736f74a0..8b4503073b0 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -82,7 +82,7 @@ pub enum TargetFeatureKind {
     Forced,
 }
 
-#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub struct TargetFeature {
     /// The name of the target feature (e.g. "avx")
     pub name: Symbol,
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 857d041224f..5367e5edd49 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -299,4 +299,43 @@ impl ScopeTree {
 
         true
     }
+
+    /// Returns the scope of non-lifetime-extended temporaries within a given scope, as well as
+    /// whether we've recorded a potential backwards-incompatible change to lint on.
+    /// Returns `None` when no enclosing temporary scope is found, such as for static items.
+    pub fn default_temporary_scope(&self, inner: Scope) -> (Option<Scope>, Option<Scope>) {
+        let mut id = inner;
+        let mut backwards_incompatible = None;
+
+        while let Some(&p) = self.parent_map.get(&id) {
+            match p.data {
+                ScopeData::Destruction => {
+                    debug!("temporary_scope({inner:?}) = {id:?} [enclosing]");
+                    return (Some(id), backwards_incompatible);
+                }
+                ScopeData::IfThenRescope | ScopeData::MatchGuard => {
+                    debug!("temporary_scope({inner:?}) = {p:?} [enclosing]");
+                    return (Some(p), backwards_incompatible);
+                }
+                ScopeData::Node
+                | ScopeData::CallSite
+                | ScopeData::Arguments
+                | ScopeData::IfThen
+                | ScopeData::Remainder(_) => {
+                    // If we haven't already passed through a backwards-incompatible node,
+                    // then check if we are passing through one now and record it if so.
+                    // This is for now only working for cases where a temporary lifetime is
+                    // *shortened*.
+                    if backwards_incompatible.is_none() {
+                        backwards_incompatible =
+                            self.backwards_incompatible_scope.get(&p.local_id).copied();
+                    }
+                    id = p
+                }
+            }
+        }
+
+        debug!("temporary_scope({inner:?}) = None");
+        (None, backwards_incompatible)
+    }
 }
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 164433aede2..5764a9c84ee 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -579,7 +579,7 @@ impl<'tcx> Display for Const<'tcx> {
 }
 
 ///////////////////////////////////////////////////////////////////////////
-/// Const-related utilities
+// Const-related utilities
 
 impl<'tcx> TyCtxt<'tcx> {
     pub fn span_as_caller_location(self, span: Span) -> ConstValue {
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 6e52bc775ef..ec2a8e86077 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -408,14 +408,14 @@ impl<'tcx> Place<'tcx> {
         self.as_ref().project_deeper(more_projections, tcx)
     }
 
-    pub fn ty_from<D: ?Sized>(
+    pub fn ty_from<D>(
         local: Local,
         projection: &[PlaceElem<'tcx>],
         local_decls: &D,
         tcx: TyCtxt<'tcx>,
     ) -> PlaceTy<'tcx>
     where
-        D: HasLocalDecls<'tcx>,
+        D: ?Sized + HasLocalDecls<'tcx>,
     {
         PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection)
     }
@@ -529,9 +529,9 @@ impl<'tcx> PlaceRef<'tcx> {
         Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
     }
 
-    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
+    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
     where
-        D: HasLocalDecls<'tcx>,
+        D: ?Sized + HasLocalDecls<'tcx>,
     {
         Place::ty_from(self.local, self.projection, local_decls, tcx)
     }
@@ -630,9 +630,9 @@ impl<'tcx> Operand<'tcx> {
         if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
     }
 
-    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
+    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
     where
-        D: HasLocalDecls<'tcx>,
+        D: ?Sized + HasLocalDecls<'tcx>,
     {
         match self {
             &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
@@ -640,9 +640,9 @@ impl<'tcx> Operand<'tcx> {
         }
     }
 
-    pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span
+    pub fn span<D>(&self, local_decls: &D) -> Span
     where
-        D: HasLocalDecls<'tcx>,
+        D: ?Sized + HasLocalDecls<'tcx>,
     {
         match self {
             &Operand::Copy(ref l) | &Operand::Move(ref l) => {
@@ -674,7 +674,7 @@ impl<'tcx> ConstOperand<'tcx> {
 }
 
 ///////////////////////////////////////////////////////////////////////////
-/// Rvalues
+// Rvalues
 
 pub enum RvalueInitializationState {
     Shallow,
@@ -721,9 +721,9 @@ impl<'tcx> Rvalue<'tcx> {
         }
     }
 
-    pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
+    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
     where
-        D: HasLocalDecls<'tcx>,
+        D: ?Sized + HasLocalDecls<'tcx>,
     {
         match *self {
             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 904d78d69b6..b498b7b8912 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1415,6 +1415,24 @@ impl PlaceContext {
         )
     }
 
+    /// Returns `true` if this place context may be used to know the address of the given place.
+    #[inline]
+    pub fn may_observe_address(self) -> bool {
+        matches!(
+            self,
+            PlaceContext::NonMutatingUse(
+                NonMutatingUseContext::SharedBorrow
+                    | NonMutatingUseContext::RawBorrow
+                    | NonMutatingUseContext::FakeBorrow
+            ) | PlaceContext::MutatingUse(
+                MutatingUseContext::Drop
+                    | MutatingUseContext::Borrow
+                    | MutatingUseContext::RawBorrow
+                    | MutatingUseContext::AsmOutput
+            )
+        )
+    }
+
     /// Returns `true` if this place context represents a storage live or storage dead marker.
     #[inline]
     pub fn is_storage_marker(self) -> bool {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 874cee54c7c..8fba218cc71 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -135,7 +135,7 @@ use crate::traits::{
 };
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::layout::ValidityRequirement;
-use crate::ty::print::{PrintTraitRefExt, describe_as_module};
+use crate::ty::print::PrintTraitRefExt;
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{
     self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, SizedTraitKind, Ty,
@@ -2731,3 +2731,12 @@ rustc_queries! {
 
 rustc_with_all_queries! { define_callbacks! }
 rustc_feedable_queries! { define_feedable! }
+
+fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String {
+    let def_id = def_id.into();
+    if def_id.is_top_level_module() {
+        "top-level module".to_string()
+    } else {
+        format!("module `{}`", tcx.def_path_str(def_id))
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 95759d1f31a..3f37595d0ee 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -216,10 +216,7 @@ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::ParamEnv<'tcx> {
 #[inline]
 fn decode_arena_allocable<'tcx, D: TyDecoder<'tcx>, T: ArenaAllocatable<'tcx> + Decodable<D>>(
     decoder: &mut D,
-) -> &'tcx T
-where
-    D: TyDecoder<'tcx>,
-{
+) -> &'tcx T {
     decoder.interner().arena.alloc(Decodable::decode(decoder))
 }
 
@@ -230,10 +227,7 @@ fn decode_arena_allocable_slice<
     T: ArenaAllocatable<'tcx> + Decodable<D>,
 >(
     decoder: &mut D,
-) -> &'tcx [T]
-where
-    D: TyDecoder<'tcx>,
-{
+) -> &'tcx [T] {
     decoder.interner().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 72ab6ac612c..218ac2cfbc1 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -38,6 +38,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState};
 use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::limit::Limit;
 use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate, find_attr};
 use rustc_index::IndexVec;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
@@ -45,14 +46,14 @@ use rustc_query_system::cache::WithDepNode;
 use rustc_query_system::dep_graph::DepNodeIndex;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
+use rustc_session::Session;
 use rustc_session::config::CrateType;
 use rustc_session::cstore::{CrateStoreDyn, Untracked};
 use rustc_session::lint::Lint;
-use rustc_session::{Limit, Session};
 use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
 use rustc_type_ir::TyKind::*;
-use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem};
+use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
 pub use rustc_type_ir::lift::Lift;
 use rustc_type_ir::{
     CollectAndApply, Interner, TypeFlags, TypeFoldable, WithCachedTypeInfo, elaborate, search_graph,
@@ -94,6 +95,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefId = DefId;
     type LocalDefId = LocalDefId;
     type TraitId = DefId;
+    type ForeignId = DefId;
+    type FunctionId = DefId;
+    type ClosureId = DefId;
+    type CoroutineClosureId = DefId;
+    type CoroutineId = DefId;
+    type AdtId = DefId;
+    type ImplId = DefId;
     type Span = Span;
 
     type GenericArgs = ty::GenericArgsRef<'tcx>;
@@ -492,6 +500,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.require_lang_item(solver_trait_lang_item_to_lang_item(lang_item), DUMMY_SP)
     }
 
+    fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> DefId {
+        self.require_lang_item(solver_adt_lang_item_to_lang_item(lang_item), DUMMY_SP)
+    }
+
     fn is_lang_item(self, def_id: DefId, lang_item: SolverLangItem) -> bool {
         self.is_lang_item(def_id, solver_lang_item_to_lang_item(lang_item))
     }
@@ -500,6 +512,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.is_lang_item(def_id, solver_trait_lang_item_to_lang_item(lang_item))
     }
 
+    fn is_adt_lang_item(self, def_id: DefId, lang_item: SolverAdtLangItem) -> bool {
+        self.is_lang_item(def_id, solver_adt_lang_item_to_lang_item(lang_item))
+    }
+
     fn is_default_trait(self, def_id: DefId) -> bool {
         self.is_default_trait(def_id)
     }
@@ -512,6 +528,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         lang_item_to_solver_trait_lang_item(self.lang_items().from_def_id(def_id)?)
     }
 
+    fn as_adt_lang_item(self, def_id: DefId) -> Option<SolverAdtLangItem> {
+        lang_item_to_solver_adt_lang_item(self.lang_items().from_def_id(def_id)?)
+    }
+
     fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
         self.associated_items(def_id)
             .in_definition_order()
@@ -738,8 +758,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         )
     }
 
-    type ProbeRef = &'tcx inspect::Probe<TyCtxt<'tcx>>;
-    fn mk_probe_ref(self, probe: inspect::Probe<Self>) -> &'tcx inspect::Probe<TyCtxt<'tcx>> {
+    type Probe = &'tcx inspect::Probe<TyCtxt<'tcx>>;
+    fn mk_probe(self, probe: inspect::Probe<Self>) -> &'tcx inspect::Probe<TyCtxt<'tcx>> {
         self.arena.alloc(probe)
     }
     fn evaluate_root_goal_for_proof_tree_raw(
@@ -783,6 +803,13 @@ bidirectional_lang_item_map! {
     DynMetadata,
     FutureOutput,
     Metadata,
+// tidy-alphabetical-end
+}
+
+bidirectional_lang_item_map! {
+    SolverAdtLangItem, lang_item_to_solver_adt_lang_item, solver_adt_lang_item_to_lang_item;
+
+// tidy-alphabetical-start
     Option,
     Poll,
 // tidy-alphabetical-end
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 3f854038651..66542525d28 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -7,6 +7,7 @@ use std::path::PathBuf;
 use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
+use rustc_hir::limit::Limit;
 use rustc_macros::extension;
 pub use rustc_type_ir::error::ExpectedFound;
 
@@ -233,7 +234,7 @@ impl<'tcx> TyCtxt<'tcx> {
         loop {
             // Look for the longest properly trimmed path that still fits in length_limit.
             short = with_forced_trimmed_paths!({
-                let mut p = FmtPrinter::new_with_limit(self, ns, rustc_session::Limit(type_limit));
+                let mut p = FmtPrinter::new_with_limit(self, ns, Limit(type_limit));
                 self.lift(t)
                     .expect("could not lift for printing")
                     .print(&mut p)
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index e567ba05f61..da17ec1f9f3 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -109,7 +109,6 @@ pub use self::typeck_results::{
     CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
     Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
 };
-pub use self::visit::*;
 use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
 use crate::metadata::ModChild;
 use crate::middle::privacy::EffectiveVisibilities;
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 59e00f85957..69dcca54f46 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -638,21 +638,7 @@ impl<'tcx> Predicate<'tcx> {
         let predicate = self.kind();
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
-            PredicateKind::Clause(ClauseKind::Projection(..))
-            | PredicateKind::Clause(ClauseKind::HostEffect(..))
-            | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
-            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
-            | PredicateKind::NormalizesTo(..)
-            | PredicateKind::AliasRelate(..)
-            | PredicateKind::Subtype(..)
-            | PredicateKind::Coerce(..)
-            | PredicateKind::Clause(ClauseKind::RegionOutlives(..))
-            | PredicateKind::Clause(ClauseKind::WellFormed(..))
-            | PredicateKind::DynCompatible(..)
-            | PredicateKind::Clause(ClauseKind::TypeOutlives(..))
-            | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
-            | PredicateKind::ConstEquate(..)
-            | PredicateKind::Ambiguous => None,
+            _ => None,
         }
     }
 
@@ -660,21 +646,7 @@ impl<'tcx> Predicate<'tcx> {
         let predicate = self.kind();
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
-            PredicateKind::Clause(ClauseKind::Trait(..))
-            | PredicateKind::Clause(ClauseKind::HostEffect(..))
-            | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
-            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
-            | PredicateKind::NormalizesTo(..)
-            | PredicateKind::AliasRelate(..)
-            | PredicateKind::Subtype(..)
-            | PredicateKind::Coerce(..)
-            | PredicateKind::Clause(ClauseKind::RegionOutlives(..))
-            | PredicateKind::Clause(ClauseKind::WellFormed(..))
-            | PredicateKind::DynCompatible(..)
-            | PredicateKind::Clause(ClauseKind::TypeOutlives(..))
-            | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
-            | PredicateKind::ConstEquate(..)
-            | PredicateKind::Ambiguous => None,
+            _ => None,
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 9e6f277ef77..d636e8ef31f 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -2,7 +2,7 @@ use hir::def::Namespace;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use tracing::{debug, instrument, trace};
 
@@ -396,16 +396,6 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
     }
 }
 
-// This is only used by query descriptions
-pub fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String {
-    let def_id = def_id.into();
-    if def_id.is_top_level_module() {
-        "top-level module".to_string()
-    } else {
-        format!("module `{}`", tcx.def_path_str(def_id))
-    }
-}
-
 impl<T> rustc_type_ir::ir_print::IrPrint<T> for TyCtxt<'_>
 where
     T: Copy + for<'a, 'tcx> Lift<TyCtxt<'tcx>, Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>>,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 74caee7336a..8101cabccdd 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -13,8 +13,8 @@ use rustc_hir::LangItem;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
 use rustc_hir::def_id::{DefIdMap, DefIdSet, LOCAL_CRATE, ModDefId};
 use rustc_hir::definitions::{DefKey, DefPathDataName};
+use rustc_hir::limit::Limit;
 use rustc_macros::{Lift, extension};
-use rustc_session::Limit;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_span::{FileNameDisplayPreference, Ident, Symbol, kw, sym};
 use rustc_type_ir::{Upcast as _, elaborate};
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
index 7dfe2d28051..8b92e48ed1a 100644
--- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -35,41 +35,8 @@ impl RvalueScopes {
         // if there's one. Static items, for instance, won't
         // have an enclosing scope, hence no scope will be
         // returned.
-        let mut id = Scope { local_id: expr_id, data: ScopeData::Node };
-        let mut backwards_incompatible = None;
-
-        while let Some(&p) = region_scope_tree.parent_map.get(&id) {
-            match p.data {
-                ScopeData::Destruction => {
-                    debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
-                    return (Some(id), backwards_incompatible);
-                }
-                ScopeData::IfThenRescope | ScopeData::MatchGuard => {
-                    debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]");
-                    return (Some(p), backwards_incompatible);
-                }
-                ScopeData::Node
-                | ScopeData::CallSite
-                | ScopeData::Arguments
-                | ScopeData::IfThen
-                | ScopeData::Remainder(_) => {
-                    // If we haven't already passed through a backwards-incompatible node,
-                    // then check if we are passing through one now and record it if so.
-                    // This is for now only working for cases where a temporary lifetime is
-                    // *shortened*.
-                    if backwards_incompatible.is_none() {
-                        backwards_incompatible = region_scope_tree
-                            .backwards_incompatible_scope
-                            .get(&p.local_id)
-                            .copied();
-                    }
-                    id = p
-                }
-            }
-        }
-
-        debug!("temporary_scope({expr_id:?}) = None");
-        (None, backwards_incompatible)
+        region_scope_tree
+            .default_temporary_scope(Scope { local_id: expr_id, data: ScopeData::Node })
     }
 
     /// Make an association between a sub-expression and an extended lifetime
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index a7d07adf78f..b8c99e83a8f 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -12,9 +12,9 @@ use rustc_hashes::Hash128;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
+use rustc_hir::limit::Limit;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
-use rustc_session::Limit;
 use rustc_span::sym;
 use rustc_type_ir::solve::SizedTraitKind;
 use smallvec::{SmallVec, smallvec};
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 3853a804a92..f0c47f257cc 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -212,42 +212,3 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
         }
     }
 }
-
-/// Finds the max universe present
-pub struct MaxUniverse {
-    max_universe: ty::UniverseIndex,
-}
-
-impl MaxUniverse {
-    pub fn new() -> Self {
-        MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
-    }
-
-    pub fn max_universe(self) -> ty::UniverseIndex {
-        self.max_universe
-    }
-}
-
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
-    fn visit_ty(&mut self, t: Ty<'tcx>) {
-        if let ty::Placeholder(placeholder) = t.kind() {
-            self.max_universe = self.max_universe.max(placeholder.universe);
-        }
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_const(&mut self, c: ty::consts::Const<'tcx>) {
-        if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
-            self.max_universe = self.max_universe.max(placeholder.universe);
-        }
-
-        c.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) {
-        if let ty::RePlaceholder(placeholder) = r.kind() {
-            self.max_universe = self.max_universe.max(placeholder.universe);
-        }
-    }
-}
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 6ec1b03a34e..5eba474a60c 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -92,7 +92,7 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_> {
         }
 
         match DefUse::for_place(*place, context) {
-            Some(DefUse::Def) => {
+            DefUse::Def => {
                 if let PlaceContext::MutatingUse(
                     MutatingUseContext::Call | MutatingUseContext::AsmOutput,
                 ) = context
@@ -105,8 +105,8 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_> {
                     self.0.kill(place.local);
                 }
             }
-            Some(DefUse::Use) => self.0.gen_(place.local),
-            None => {}
+            DefUse::Use => self.0.gen_(place.local),
+            DefUse::PartialWrite | DefUse::NonUse => {}
         }
 
         self.visit_projection(place.as_ref(), context, location);
@@ -131,23 +131,29 @@ impl<'tcx> Visitor<'tcx> for YieldResumeEffect<'_> {
 }
 
 #[derive(Eq, PartialEq, Clone)]
-enum DefUse {
+pub enum DefUse {
+    /// Full write to the local.
     Def,
+    /// Read of any part of the local.
     Use,
+    /// Partial write to the local.
+    PartialWrite,
+    /// Non-use, like debuginfo.
+    NonUse,
 }
 
 impl DefUse {
     fn apply(state: &mut DenseBitSet<Local>, place: Place<'_>, context: PlaceContext) {
         match DefUse::for_place(place, context) {
-            Some(DefUse::Def) => state.kill(place.local),
-            Some(DefUse::Use) => state.gen_(place.local),
-            None => {}
+            DefUse::Def => state.kill(place.local),
+            DefUse::Use => state.gen_(place.local),
+            DefUse::PartialWrite | DefUse::NonUse => {}
         }
     }
 
-    fn for_place(place: Place<'_>, context: PlaceContext) -> Option<DefUse> {
+    pub fn for_place(place: Place<'_>, context: PlaceContext) -> DefUse {
         match context {
-            PlaceContext::NonUse(_) => None,
+            PlaceContext::NonUse(_) => DefUse::NonUse,
 
             PlaceContext::MutatingUse(
                 MutatingUseContext::Call
@@ -156,21 +162,20 @@ impl DefUse {
                 | MutatingUseContext::Store
                 | MutatingUseContext::Deinit,
             ) => {
+                // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
                 if place.is_indirect() {
-                    // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a
-                    // use.
-                    Some(DefUse::Use)
+                    DefUse::Use
                 } else if place.projection.is_empty() {
-                    Some(DefUse::Def)
+                    DefUse::Def
                 } else {
-                    None
+                    DefUse::PartialWrite
                 }
             }
 
             // Setting the discriminant is not a use because it does no reading, but it is also not
             // a def because it does not overwrite the whole place
             PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant) => {
-                place.is_indirect().then_some(DefUse::Use)
+                if place.is_indirect() { DefUse::Use } else { DefUse::PartialWrite }
             }
 
             // All other contexts are uses...
@@ -188,7 +193,7 @@ impl DefUse {
                 | NonMutatingUseContext::PlaceMention
                 | NonMutatingUseContext::FakeBorrow
                 | NonMutatingUseContext::SharedBorrow,
-            ) => Some(DefUse::Use),
+            ) => DefUse::Use,
 
             PlaceContext::MutatingUse(MutatingUseContext::Projection)
             | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 3f29b819a6d..6d573e1c00e 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -9,7 +9,8 @@ pub use self::initialized::{
     MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
 };
 pub use self::liveness::{
-    MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,
+    DefUse, MaybeLiveLocals, MaybeTransitiveLiveLocals,
+    TransferFunction as LivenessTransferFunction,
 };
 pub use self::storage_liveness::{
     MaybeRequiresStorage, MaybeStorageDead, MaybeStorageLive, always_storage_live_locals,
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index 70d1a34b5fb..e3d1e04a319 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -1,9 +1,5 @@
-use rustc_index::bit_set::DenseBitSet;
-use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::{Idx, IndexVec};
-use rustc_middle::mir::{self, BasicBlock, Body, Location};
-
-use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
+use rustc_middle::mir::{BasicBlock, Body, Location};
 
 /// Maps between a `Location` and a `PointIndex` (and vice versa).
 pub struct DenseLocationMap {
@@ -93,65 +89,3 @@ rustc_index::newtype_index! {
     #[debug_format = "PointIndex({})"]
     pub struct PointIndex {}
 }
-
-/// Add points depending on the result of the given dataflow analysis.
-pub fn save_as_intervals<'tcx, N, A>(
-    elements: &DenseLocationMap,
-    body: &mir::Body<'tcx>,
-    mut analysis: A,
-    results: Results<A::Domain>,
-) -> SparseIntervalMatrix<N, PointIndex>
-where
-    N: Idx,
-    A: Analysis<'tcx, Domain = DenseBitSet<N>>,
-{
-    let values = SparseIntervalMatrix::new(elements.num_points());
-    let mut visitor = Visitor { elements, values };
-    visit_results(
-        body,
-        body.basic_blocks.reverse_postorder().iter().copied(),
-        &mut analysis,
-        &results,
-        &mut visitor,
-    );
-    visitor.values
-}
-
-struct Visitor<'a, N: Idx> {
-    elements: &'a DenseLocationMap,
-    values: SparseIntervalMatrix<N, PointIndex>,
-}
-
-impl<'tcx, A, N> ResultsVisitor<'tcx, A> for Visitor<'_, N>
-where
-    A: Analysis<'tcx, Domain = DenseBitSet<N>>,
-    N: Idx,
-{
-    fn visit_after_primary_statement_effect<'mir>(
-        &mut self,
-        _analysis: &mut A,
-        state: &A::Domain,
-        _statement: &'mir mir::Statement<'tcx>,
-        location: Location,
-    ) {
-        let point = self.elements.point_from_location(location);
-        // Use internal iterator manually as it is much more efficient.
-        state.iter().for_each(|node| {
-            self.values.insert(node, point);
-        });
-    }
-
-    fn visit_after_primary_terminator_effect<'mir>(
-        &mut self,
-        _analysis: &mut A,
-        state: &A::Domain,
-        _terminator: &'mir mir::Terminator<'tcx>,
-        location: Location,
-    ) {
-        let point = self.elements.point_from_location(location);
-        // Use internal iterator manually as it is much more efficient.
-        state.iter().for_each(|node| {
-            self.values.insert(node, point);
-        });
-    }
-}
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 005e7973130..9a00831dc01 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::DenseBitSet;
-use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use tracing::debug;
@@ -917,12 +917,7 @@ pub fn excluded_locals(body: &Body<'_>) -> DenseBitSet<Local> {
 
     impl<'tcx> Visitor<'tcx> for Collector {
         fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-            if (context.is_borrow()
-                || context.is_address_of()
-                || context.is_drop()
-                || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput))
-                && !place.is_indirect()
-            {
+            if context.may_observe_address() && !place.is_indirect() {
                 // A pointer to a place could be used to access other places with the same local,
                 // hence we have to exclude the local completely.
                 self.result.insert(place.local);
diff --git a/compiler/rustc_mir_transform/src/check_inline_always_target_features.rs b/compiler/rustc_mir_transform/src/check_inline_always_target_features.rs
new file mode 100644
index 00000000000..abad28f0a8f
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/check_inline_always_target_features.rs
@@ -0,0 +1,88 @@
+use rustc_hir::attrs::InlineAttr;
+use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
+use rustc_middle::mir::{Body, TerminatorKind};
+use rustc_middle::ty::{self, TyCtxt};
+
+use crate::pass_manager::MirLint;
+
+pub(super) struct CheckInlineAlwaysTargetFeature;
+
+impl<'tcx> MirLint<'tcx> for CheckInlineAlwaysTargetFeature {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+        check_inline_always_target_features(tcx, body)
+    }
+}
+
+/// `#[target_feature]`-annotated functions can be marked `#[inline]` and will only be inlined if
+/// the target features match (as well as all of the other inlining heuristics). `#[inline(always)]`
+/// will always inline regardless of matching target features, which can result in errors from LLVM.
+/// However, it is desirable to be able to always annotate certain functions (e.g. SIMD intrinsics)
+/// as `#[inline(always)]` but check the target features match in Rust to avoid the LLVM errors.
+///
+/// We check the caller and callee target features to ensure that this can
+/// be done or emit a lint.
+#[inline]
+fn check_inline_always_target_features<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+    let caller_def_id = body.source.def_id().expect_local();
+    if !tcx.def_kind(caller_def_id).has_codegen_attrs() {
+        return;
+    }
+
+    let caller_codegen_fn_attrs = tcx.codegen_fn_attrs(caller_def_id);
+
+    for bb in body.basic_blocks.iter() {
+        let terminator = bb.terminator();
+        match &terminator.kind {
+            TerminatorKind::Call { func, .. } | TerminatorKind::TailCall { func, .. } => {
+                let fn_ty = func.ty(body, tcx);
+                let ty::FnDef(callee_def_id, _) = *fn_ty.kind() else {
+                    continue;
+                };
+
+                if !tcx.def_kind(callee_def_id).has_codegen_attrs() {
+                    continue;
+                }
+                let callee_codegen_fn_attrs = tcx.codegen_fn_attrs(callee_def_id);
+                if callee_codegen_fn_attrs.inline != InlineAttr::Always
+                    || callee_codegen_fn_attrs.target_features.is_empty()
+                {
+                    continue;
+                }
+
+                // Scan the users defined target features and ensure they
+                // match the caller.
+                if tcx.is_target_feature_call_safe(
+                    &callee_codegen_fn_attrs.target_features,
+                    &caller_codegen_fn_attrs
+                        .target_features
+                        .iter()
+                        .cloned()
+                        .chain(tcx.sess.target_features.iter().map(|feat| TargetFeature {
+                            name: *feat,
+                            kind: TargetFeatureKind::Implied,
+                        }))
+                        .collect::<Vec<_>>(),
+                ) {
+                    continue;
+                }
+
+                let callee_only: Vec<_> = callee_codegen_fn_attrs
+                    .target_features
+                    .iter()
+                    .filter(|it| !caller_codegen_fn_attrs.target_features.contains(it))
+                    .filter(|it| !matches!(it.kind, TargetFeatureKind::Implied))
+                    .map(|it| it.name.as_str())
+                    .collect();
+
+                crate::errors::emit_inline_always_target_feature_diagnostic(
+                    tcx,
+                    terminator.source_info.span,
+                    callee_def_id,
+                    caller_def_id.into(),
+                    &callee_only,
+                );
+            }
+            _ => (),
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/coverage/expansion.rs b/compiler/rustc_mir_transform/src/coverage/expansion.rs
index 91e0528f52f..851bbaeed48 100644
--- a/compiler/rustc_mir_transform/src/coverage/expansion.rs
+++ b/compiler/rustc_mir_transform/src/coverage/expansion.rs
@@ -82,7 +82,7 @@ impl ExpnNode {
         Self {
             expn_id,
 
-            expn_kind: expn_data.kind.clone(),
+            expn_kind: expn_data.kind,
             call_site,
             call_site_expn_id,
 
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index b186c2bd775..df98c07f549 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -135,7 +135,16 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
                     }
                 }
             }
-            TerminatorKind::Call { unwind, .. } => {
+            TerminatorKind::Call { ref func, unwind, .. } => {
+                // We track calls because they make our function not a leaf (and in theory, the
+                // number of calls indicates how likely this function is to perturb other CGUs).
+                // But intrinsics don't have a body that gets assigned to a CGU, so they are
+                // ignored.
+                if let Some((fn_def_id, _)) = func.const_fn_def()
+                    && self.tcx.has_attr(fn_def_id, sym::rustc_intrinsic)
+                {
+                    return;
+                }
                 self.calls += 1;
                 if let UnwindAction::Cleanup(_) = unwind {
                     self.landing_pads += 1;
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index cf7425251e8..9ba2d274691 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -59,6 +59,12 @@
 //! The first two conditions are simple structural requirements on the `Assign` statements that can
 //! be trivially checked. The third requirement however is more difficult and costly to check.
 //!
+//! ## Current implementation
+//!
+//! The current implementation relies on live range computation to check for conflicts. We only
+//! allow to merge locals that have disjoint live ranges. The live range are defined with
+//! half-statement granularity, so as to make all writes be live for at least a half statement.
+//!
 //! ## Future Improvements
 //!
 //! There are a number of ways in which this pass could be improved in the future:
@@ -117,9 +123,8 @@
 //! - Layout optimizations for coroutines have been added to improve code generation for
 //!   async/await, which are very similar in spirit to what this optimization does.
 //!
-//! Also, rustc now has a simple NRVO pass (see `nrvo.rs`), which handles a subset of the cases that
-//! this destination propagation pass handles, proving that similar optimizations can be performed
-//! on MIR.
+//! [The next approach][attempt 4] computes a conflict matrix between locals by forbidding merging
+//! locals with competing writes or with one write while the other is live.
 //!
 //! ## Pre/Post Optimization
 //!
@@ -130,20 +135,18 @@
 //! [attempt 1]: https://github.com/rust-lang/rust/pull/47954
 //! [attempt 2]: https://github.com/rust-lang/rust/pull/71003
 //! [attempt 3]: https://github.com/rust-lang/rust/pull/72632
+//! [attempt 4]: https://github.com/rust-lang/rust/pull/96451
 
-use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry};
+use rustc_data_structures::union_find::UnionFind;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_index::interval::SparseIntervalMatrix;
-use rustc_middle::bug;
+use rustc_index::{IndexVec, newtype_index};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
-use rustc_middle::mir::{
-    Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location, MirDumper, Operand,
-    PassWhere, Place, Rvalue, Statement, StatementKind, TerminatorKind, traversal,
-};
+use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
-use rustc_mir_dataflow::Analysis;
-use rustc_mir_dataflow::impls::MaybeLiveLocals;
-use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex, save_as_intervals};
+use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals};
+use rustc_mir_dataflow::points::DenseLocationMap;
+use rustc_mir_dataflow::{Analysis, Results};
 use tracing::{debug, trace};
 
 pub(super) struct DestinationPropagation;
@@ -161,84 +164,81 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
         sess.mir_opt_level() >= 3
     }
 
+    #[tracing::instrument(level = "trace", skip(self, tcx, body))]
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let def_id = body.source.def_id();
-        let mut candidates = Candidates::default();
-        let mut write_info = WriteInfo::default();
-        trace!(func = ?tcx.def_path_str(def_id));
+        trace!(?def_id);
 
         let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
 
+        let candidates = Candidates::find(body, &borrowed);
+        trace!(?candidates);
+        if candidates.c.is_empty() {
+            return;
+        }
+
         let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp"));
+
         let points = DenseLocationMap::new(body);
-        let mut live = save_as_intervals(&points, body, live.analysis, live.results);
-
-        // In order to avoid having to collect data for every single pair of locals in the body, we
-        // do not allow doing more than one merge for places that are derived from the same local at
-        // once. To avoid missed opportunities, we instead iterate to a fixed point - we'll refer to
-        // each of these iterations as a "round."
-        //
-        // Reaching a fixed point could in theory take up to `min(l, s)` rounds - however, we do not
-        // expect to see MIR like that. To verify this, a test was run against `[rust-lang/regex]` -
-        // the average MIR body saw 1.32 full iterations of this loop. The most that was hit were 30
-        // for a single function. Only 80/2801 (2.9%) of functions saw at least 5.
-        //
-        // [rust-lang/regex]:
-        //     https://github.com/rust-lang/regex/tree/b5372864e2df6a2f5e543a556a62197f50ca3650
-        let mut round_count = 0;
-        loop {
-            // PERF: Can we do something smarter than recalculating the candidates and liveness
-            // results?
-            candidates.reset_and_find(body, &borrowed);
-            trace!(?candidates);
-            dest_prop_mir_dump(tcx, body, &points, &live, round_count);
-
-            FilterInformation::filter_liveness(
-                &mut candidates,
-                &points,
-                &live,
-                &mut write_info,
-                body,
-            );
-
-            // Because we only filter once per round, it is unsound to use a local for more than
-            // one merge operation within a single round of optimizations. We store here which ones
-            // we have already used.
-            let mut merged_locals: DenseBitSet<Local> =
-                DenseBitSet::new_empty(body.local_decls.len());
-
-            // This is the set of merges we will apply this round. It is a subset of the candidates.
-            let mut merges = FxIndexMap::default();
-
-            for (src, candidates) in candidates.c.iter() {
-                if merged_locals.contains(*src) {
-                    continue;
-                }
-                let Some(dest) = candidates.iter().find(|dest| !merged_locals.contains(**dest))
-                else {
-                    continue;
-                };
-
-                // Replace `src` by `dest` everywhere.
-                merges.insert(*src, *dest);
-                merged_locals.insert(*src);
-                merged_locals.insert(*dest);
-
-                // Update liveness information based on the merge we just performed.
-                // Every location where `src` was live, `dest` will be live.
-                live.union_rows(*src, *dest);
+        let mut relevant = RelevantLocals::compute(&candidates, body.local_decls.len());
+        let mut live = save_as_intervals(&points, body, &relevant, live.results);
+
+        dest_prop_mir_dump(tcx, body, &points, &live, &relevant);
+
+        let mut merged_locals = DenseBitSet::new_empty(body.local_decls.len());
+
+        for (src, dst) in candidates.c.into_iter() {
+            trace!(?src, ?dst);
+
+            let Some(mut src) = relevant.find(src) else { continue };
+            let Some(mut dst) = relevant.find(dst) else { continue };
+            if src == dst {
+                continue;
             }
-            trace!(merging = ?merges);
 
-            if merges.is_empty() {
-                break;
+            let Some(src_live_ranges) = live.row(src) else { continue };
+            let Some(dst_live_ranges) = live.row(dst) else { continue };
+            trace!(?src, ?src_live_ranges);
+            trace!(?dst, ?dst_live_ranges);
+
+            if src_live_ranges.disjoint(dst_live_ranges) {
+                // We want to replace `src` by `dst`.
+                let mut orig_src = relevant.original[src];
+                let mut orig_dst = relevant.original[dst];
+
+                // The return place and function arguments are required and cannot be renamed.
+                // This check cannot be made during candidate collection, as we may want to
+                // unify the same non-required local with several required locals.
+                match (is_local_required(orig_src, body), is_local_required(orig_dst, body)) {
+                    // Renaming `src` is ok.
+                    (false, _) => {}
+                    // Renaming `src` is wrong, but renaming `dst` is ok.
+                    (true, false) => {
+                        std::mem::swap(&mut src, &mut dst);
+                        std::mem::swap(&mut orig_src, &mut orig_dst);
+                    }
+                    // Neither local can be renamed, so skip this case.
+                    (true, true) => continue,
+                }
+
+                trace!(?src, ?dst, "merge");
+                merged_locals.insert(orig_src);
+                merged_locals.insert(orig_dst);
+
+                // Replace `src` by `dst`.
+                let head = relevant.union(src, dst);
+                live.union_rows(/* read */ src, /* write */ head);
+                live.union_rows(/* read */ dst, /* write */ head);
             }
-            round_count += 1;
+        }
+        trace!(?merged_locals);
+        trace!(?relevant.renames);
 
-            apply_merges(body, tcx, merges, merged_locals);
+        if merged_locals.is_empty() {
+            return;
         }
 
-        trace!(round_count);
+        apply_merges(body, tcx, relevant, merged_locals);
     }
 
     fn is_required(&self) -> bool {
@@ -246,30 +246,6 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
     }
 }
 
-#[derive(Debug, Default)]
-struct Candidates {
-    /// The set of candidates we are considering in this optimization.
-    ///
-    /// We will always merge the key into at most one of its values.
-    ///
-    /// Whether a place ends up in the key or the value does not correspond to whether it appears as
-    /// the lhs or rhs of any assignment. As a matter of fact, the places in here might never appear
-    /// in an assignment at all. This happens because if we see an assignment like this:
-    ///
-    /// ```ignore (syntax-highlighting-only)
-    /// _1.0 = _2.0
-    /// ```
-    ///
-    /// We will still report that we would like to merge `_1` and `_2` in an attempt to allow us to
-    /// remove that assignment.
-    c: FxIndexMap<Local, Vec<Local>>,
-
-    /// A reverse index of the `c` set; if the `c` set contains `a => Place { local: b, proj }`,
-    /// then this contains `b => a`.
-    // PERF: Possibly these should be `SmallVec`s?
-    reverse: FxIndexMap<Local, Vec<Local>>,
-}
-
 //////////////////////////////////////////////////////////
 // Merging
 //
@@ -278,16 +254,16 @@ struct Candidates {
 fn apply_merges<'tcx>(
     body: &mut Body<'tcx>,
     tcx: TyCtxt<'tcx>,
-    merges: FxIndexMap<Local, Local>,
+    relevant: RelevantLocals,
     merged_locals: DenseBitSet<Local>,
 ) {
-    let mut merger = Merger { tcx, merges, merged_locals };
+    let mut merger = Merger { tcx, relevant, merged_locals };
     merger.visit_body_preserves_cfg(body);
 }
 
 struct Merger<'tcx> {
     tcx: TyCtxt<'tcx>,
-    merges: FxIndexMap<Local, Local>,
+    relevant: RelevantLocals,
     merged_locals: DenseBitSet<Local>,
 }
 
@@ -297,8 +273,8 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
     }
 
     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _location: Location) {
-        if let Some(dest) = self.merges.get(local) {
-            *local = *dest;
+        if let Some(relevant) = self.relevant.find(*local) {
+            *local = self.relevant.original[relevant];
         }
     }
 
@@ -336,414 +312,95 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
 }
 
 //////////////////////////////////////////////////////////
-// Liveness filtering
+// Relevant locals
 //
-// This section enforces bullet point 2
+// Small utility to reduce size of the conflict matrix by only considering locals that appear in
+// the candidates
 
-struct FilterInformation<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    points: &'a DenseLocationMap,
-    live: &'a SparseIntervalMatrix<Local, PointIndex>,
-    candidates: &'a mut Candidates,
-    write_info: &'a mut WriteInfo,
-    at: Location,
+newtype_index! {
+    /// Represent a subset of locals which appear in candidates.
+    struct RelevantLocal {}
 }
 
-// We first implement some utility functions which we will expose removing candidates according to
-// different needs. Throughout the liveness filtering, the `candidates` are only ever accessed
-// through these methods, and not directly.
-impl Candidates {
-    /// Collects the candidates for merging.
-    ///
-    /// This is responsible for enforcing the first and third bullet point.
-    fn reset_and_find<'tcx>(&mut self, body: &Body<'tcx>, borrowed: &DenseBitSet<Local>) {
-        self.c.clear();
-        self.reverse.clear();
-        let mut visitor = FindAssignments { body, candidates: &mut self.c, borrowed };
-        visitor.visit_body(body);
-        // Deduplicate candidates.
-        for (_, cands) in self.c.iter_mut() {
-            cands.sort();
-            cands.dedup();
-        }
-        // Generate the reverse map.
-        for (src, cands) in self.c.iter() {
-            for dest in cands.iter().copied() {
-                self.reverse.entry(dest).or_default().push(*src);
-            }
-        }
-    }
-
-    /// Just `Vec::retain`, but the condition is inverted and we add debugging output
-    fn vec_filter_candidates(
-        src: Local,
-        v: &mut Vec<Local>,
-        mut f: impl FnMut(Local) -> CandidateFilter,
-        at: Location,
-    ) {
-        v.retain(|dest| {
-            let remove = f(*dest);
-            if remove == CandidateFilter::Remove {
-                trace!("eliminating {:?} => {:?} due to conflict at {:?}", src, dest, at);
-            }
-            remove == CandidateFilter::Keep
-        });
-    }
-
-    /// `vec_filter_candidates` but for an `Entry`
-    fn entry_filter_candidates(
-        mut entry: IndexOccupiedEntry<'_, Local, Vec<Local>>,
-        p: Local,
-        f: impl FnMut(Local) -> CandidateFilter,
-        at: Location,
-    ) {
-        let candidates = entry.get_mut();
-        Self::vec_filter_candidates(p, candidates, f, at);
-        if candidates.len() == 0 {
-            // FIXME(#120456) - is `swap_remove` correct?
-            entry.swap_remove();
-        }
-    }
-
-    /// For all candidates `(p, q)` or `(q, p)` removes the candidate if `f(q)` says to do so
-    fn filter_candidates_by(
-        &mut self,
-        p: Local,
-        mut f: impl FnMut(Local) -> CandidateFilter,
-        at: Location,
-    ) {
-        // Cover the cases where `p` appears as a `src`
-        if let IndexEntry::Occupied(entry) = self.c.entry(p) {
-            Self::entry_filter_candidates(entry, p, &mut f, at);
-        }
-        // And the cases where `p` appears as a `dest`
-        let Some(srcs) = self.reverse.get_mut(&p) else {
-            return;
-        };
-        // We use `retain` here to remove the elements from the reverse set if we've removed the
-        // matching candidate in the forward set.
-        srcs.retain(|src| {
-            if f(*src) == CandidateFilter::Keep {
-                return true;
-            }
-            let IndexEntry::Occupied(entry) = self.c.entry(*src) else {
-                return false;
-            };
-            Self::entry_filter_candidates(
-                entry,
-                *src,
-                |dest| {
-                    if dest == p { CandidateFilter::Remove } else { CandidateFilter::Keep }
-                },
-                at,
-            );
-            false
-        });
-    }
+#[derive(Debug)]
+struct RelevantLocals {
+    original: IndexVec<RelevantLocal, Local>,
+    shrink: IndexVec<Local, Option<RelevantLocal>>,
+    renames: UnionFind<RelevantLocal>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
-enum CandidateFilter {
-    Keep,
-    Remove,
-}
+impl RelevantLocals {
+    #[tracing::instrument(level = "trace", skip(candidates, num_locals), ret)]
+    fn compute(candidates: &Candidates, num_locals: usize) -> RelevantLocals {
+        let mut original = IndexVec::with_capacity(candidates.c.len());
+        let mut shrink = IndexVec::from_elem_n(None, num_locals);
 
-impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
-    /// Filters the set of candidates to remove those that conflict.
-    ///
-    /// The steps we take are exactly those that are outlined at the top of the file. For each
-    /// statement/terminator, we collect the set of locals that are written to in that
-    /// statement/terminator, and then we remove all pairs of candidates that contain one such local
-    /// and another one that is live.
-    ///
-    /// We need to be careful about the ordering of operations within each statement/terminator
-    /// here. Many statements might write and read from more than one place, and we need to consider
-    /// them all. The strategy for doing this is as follows: We first gather all the places that are
-    /// written to within the statement/terminator via `WriteInfo`. Then, we use the liveness
-    /// analysis from *before* the statement/terminator (in the control flow sense) to eliminate
-    /// candidates - this is because we want to conservatively treat a pair of locals that is both
-    /// read and written in the statement/terminator to be conflicting, and the liveness analysis
-    /// before the statement/terminator will correctly report locals that are read in the
-    /// statement/terminator to be live. We are additionally conservative by treating all written to
-    /// locals as also being read from.
-    fn filter_liveness(
-        candidates: &mut Candidates,
-        points: &DenseLocationMap,
-        live: &SparseIntervalMatrix<Local, PointIndex>,
-        write_info: &mut WriteInfo,
-        body: &Body<'tcx>,
-    ) {
-        let mut this = FilterInformation {
-            body,
-            points,
-            live,
-            candidates,
-            // We don't actually store anything at this scope, we just keep things here to be able
-            // to reuse the allocation.
-            write_info,
-            // Doesn't matter what we put here, will be overwritten before being used
-            at: Location::START,
+        // Mark a local as relevant and record it into the maps.
+        let mut declare = |local| {
+            shrink.get_or_insert_with(local, || original.push(local));
         };
-        this.internal_filter_liveness();
-    }
 
-    fn internal_filter_liveness(&mut self) {
-        for (block, data) in traversal::preorder(self.body) {
-            self.at = Location { block, statement_index: data.statements.len() };
-            self.write_info.for_terminator(&data.terminator().kind);
-            self.apply_conflicts();
-
-            for (i, statement) in data.statements.iter().enumerate().rev() {
-                self.at = Location { block, statement_index: i };
-                self.write_info.for_statement(&statement.kind, self.body);
-                self.apply_conflicts();
-            }
+        for &(src, dest) in candidates.c.iter() {
+            declare(src);
+            declare(dest)
         }
-    }
 
-    fn apply_conflicts(&mut self) {
-        let writes = &self.write_info.writes;
-        for p in writes {
-            let other_skip = self.write_info.skip_pair.and_then(|(a, b)| {
-                if a == *p {
-                    Some(b)
-                } else if b == *p {
-                    Some(a)
-                } else {
-                    None
-                }
-            });
-            let at = self.points.point_from_location(self.at);
-            self.candidates.filter_candidates_by(
-                *p,
-                |q| {
-                    if Some(q) == other_skip {
-                        return CandidateFilter::Keep;
-                    }
-                    // It is possible that a local may be live for less than the
-                    // duration of a statement This happens in the case of function
-                    // calls or inline asm. Because of this, we also mark locals as
-                    // conflicting when both of them are written to in the same
-                    // statement.
-                    if self.live.contains(q, at) || writes.contains(&q) {
-                        CandidateFilter::Remove
-                    } else {
-                        CandidateFilter::Keep
-                    }
-                },
-                self.at,
-            );
-        }
+        let renames = UnionFind::new(original.len());
+        RelevantLocals { original, shrink, renames }
     }
-}
 
-/// Describes where a statement/terminator writes to
-#[derive(Default, Debug)]
-struct WriteInfo {
-    writes: Vec<Local>,
-    /// If this pair of locals is a candidate pair, completely skip processing it during this
-    /// statement. All other candidates are unaffected.
-    skip_pair: Option<(Local, Local)>,
-}
-
-impl WriteInfo {
-    fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'tcx>) {
-        self.reset();
-        match statement {
-            StatementKind::Assign(box (lhs, rhs)) => {
-                self.add_place(*lhs);
-                match rhs {
-                    Rvalue::Use(op) => {
-                        self.add_operand(op);
-                        self.consider_skipping_for_assign_use(*lhs, op, body);
-                    }
-                    Rvalue::Repeat(op, _) => {
-                        self.add_operand(op);
-                    }
-                    Rvalue::Cast(_, op, _)
-                    | Rvalue::UnaryOp(_, op)
-                    | Rvalue::ShallowInitBox(op, _) => {
-                        self.add_operand(op);
-                    }
-                    Rvalue::BinaryOp(_, ops) => {
-                        for op in [&ops.0, &ops.1] {
-                            self.add_operand(op);
-                        }
-                    }
-                    Rvalue::Aggregate(_, ops) => {
-                        for op in ops {
-                            self.add_operand(op);
-                        }
-                    }
-                    Rvalue::WrapUnsafeBinder(op, _) => {
-                        self.add_operand(op);
-                    }
-                    Rvalue::ThreadLocalRef(_)
-                    | Rvalue::NullaryOp(_, _)
-                    | Rvalue::Ref(_, _, _)
-                    | Rvalue::RawPtr(_, _)
-                    | Rvalue::Len(_)
-                    | Rvalue::Discriminant(_)
-                    | Rvalue::CopyForDeref(_) => {}
-                }
-            }
-            // Retags are technically also reads, but reporting them as a write suffices
-            StatementKind::SetDiscriminant { place, .. }
-            | StatementKind::Deinit(place)
-            | StatementKind::Retag(_, place) => {
-                self.add_place(**place);
-            }
-            StatementKind::Intrinsic(_)
-            | StatementKind::ConstEvalCounter
-            | StatementKind::Nop
-            | StatementKind::Coverage(_)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_)
-            | StatementKind::BackwardIncompatibleDropHint { .. }
-            | StatementKind::PlaceMention(_) => {}
-            StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
-                bug!("{:?} not found in this MIR phase", statement)
-            }
-        }
+    fn find(&mut self, src: Local) -> Option<RelevantLocal> {
+        let src = self.shrink[src]?;
+        let src = self.renames.find(src);
+        Some(src)
     }
 
-    fn consider_skipping_for_assign_use<'tcx>(
-        &mut self,
-        lhs: Place<'tcx>,
-        rhs: &Operand<'tcx>,
-        body: &Body<'tcx>,
-    ) {
-        let Some(rhs) = rhs.place() else { return };
-        if let Some(pair) = places_to_candidate_pair(lhs, rhs, body) {
-            self.skip_pair = Some(pair);
-        }
-    }
-
-    fn for_terminator<'tcx>(&mut self, terminator: &TerminatorKind<'tcx>) {
-        self.reset();
-        match terminator {
-            TerminatorKind::SwitchInt { discr: op, .. }
-            | TerminatorKind::Assert { cond: op, .. } => {
-                self.add_operand(op);
-            }
-            TerminatorKind::Call { destination, func, args, .. } => {
-                self.add_place(*destination);
-                self.add_operand(func);
-                for arg in args {
-                    self.add_operand(&arg.node);
-                }
-            }
-            TerminatorKind::TailCall { func, args, .. } => {
-                self.add_operand(func);
-                for arg in args {
-                    self.add_operand(&arg.node);
-                }
-            }
-            TerminatorKind::InlineAsm { operands, .. } => {
-                for asm_operand in operands {
-                    match asm_operand {
-                        InlineAsmOperand::In { value, .. } => {
-                            self.add_operand(value);
-                        }
-                        InlineAsmOperand::Out { place, .. } => {
-                            if let Some(place) = place {
-                                self.add_place(*place);
-                            }
-                        }
-                        // Note that the `late` field in `InOut` is about whether the registers used
-                        // for these things overlap, and is of absolutely no interest to us.
-                        InlineAsmOperand::InOut { in_value, out_place, .. } => {
-                            if let Some(place) = out_place {
-                                self.add_place(*place);
-                            }
-                            self.add_operand(in_value);
-                        }
-                        InlineAsmOperand::Const { .. }
-                        | InlineAsmOperand::SymFn { .. }
-                        | InlineAsmOperand::SymStatic { .. }
-                        | InlineAsmOperand::Label { .. } => {}
-                    }
-                }
-            }
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::UnwindResume
-            | TerminatorKind::UnwindTerminate(_)
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable { .. } => (),
-            TerminatorKind::Drop { .. } => {
-                // `Drop`s create a `&mut` and so are not considered
-            }
-            TerminatorKind::Yield { .. }
-            | TerminatorKind::CoroutineDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {
-                bug!("{:?} not found in this MIR phase", terminator)
-            }
-        }
-    }
-
-    fn add_place(&mut self, place: Place<'_>) {
-        self.writes.push(place.local);
-    }
-
-    fn add_operand<'tcx>(&mut self, op: &Operand<'tcx>) {
-        match op {
-            // FIXME(JakobDegen): In a previous version, the `Move` case was incorrectly treated as
-            // being a read only. This was unsound, however we cannot add a regression test because
-            // it is not possible to set this off with current MIR. Once we have that ability, a
-            // regression test should be added.
-            Operand::Move(p) => self.add_place(*p),
-            Operand::Copy(_) | Operand::Constant(_) => (),
-        }
-    }
-
-    fn reset(&mut self) {
-        self.writes.clear();
-        self.skip_pair = None;
+    fn union(&mut self, lhs: RelevantLocal, rhs: RelevantLocal) -> RelevantLocal {
+        let head = self.renames.unify(lhs, rhs);
+        // We need to ensure we keep the original local of the RHS, as it may be a required local.
+        self.original[head] = self.original[rhs];
+        head
     }
 }
 
 /////////////////////////////////////////////////////
 // Candidate accumulation
 
-/// If the pair of places is being considered for merging, returns the candidate which would be
-/// merged in order to accomplish this.
-///
-/// The contract here is in one direction - there is a guarantee that merging the locals that are
-/// outputted by this function would result in an assignment between the inputs becoming a
-/// self-assignment. However, there is no guarantee that the returned pair is actually suitable for
-/// merging - candidate collection must still check this independently.
-///
-/// This output is unique for each unordered pair of input places.
-fn places_to_candidate_pair<'tcx>(
-    a: Place<'tcx>,
-    b: Place<'tcx>,
-    body: &Body<'tcx>,
-) -> Option<(Local, Local)> {
-    let (mut a, mut b) = if a.projection.len() == 0 && b.projection.len() == 0 {
-        (a.local, b.local)
-    } else {
-        return None;
-    };
+#[derive(Debug, Default)]
+struct Candidates {
+    /// The set of candidates we are considering in this optimization.
+    ///
+    /// Whether a place ends up in the key or the value does not correspond to whether it appears as
+    /// the lhs or rhs of any assignment. As a matter of fact, the places in here might never appear
+    /// in an assignment at all. This happens because if we see an assignment like this:
+    ///
+    /// ```ignore (syntax-highlighting-only)
+    /// _1.0 = _2.0
+    /// ```
+    ///
+    /// We will still report that we would like to merge `_1` and `_2` in an attempt to allow us to
+    /// remove that assignment.
+    c: Vec<(Local, Local)>,
+}
 
-    // By sorting, we make sure we're input order independent
-    if a > b {
-        std::mem::swap(&mut a, &mut b);
-    }
+// We first implement some utility functions which we will expose removing candidates according to
+// different needs. Throughout the liveness filtering, the `candidates` are only ever accessed
+// through these methods, and not directly.
+impl Candidates {
+    /// Collects the candidates for merging.
+    ///
+    /// This is responsible for enforcing the first and third bullet point.
+    fn find(body: &Body<'_>, borrowed: &DenseBitSet<Local>) -> Candidates {
+        let mut visitor = FindAssignments { body, candidates: Default::default(), borrowed };
+        visitor.visit_body(body);
 
-    // We could now return `(a, b)`, but then we miss some candidates in the case where `a` can't be
-    // used as a `src`.
-    if is_local_required(a, body) {
-        std::mem::swap(&mut a, &mut b);
+        Candidates { c: visitor.candidates }
     }
-    // We could check `is_local_required` again here, but there's no need - after all, we make no
-    // promise that the candidate pair is actually valid
-    Some((a, b))
 }
 
 struct FindAssignments<'a, 'tcx> {
     body: &'a Body<'tcx>,
-    candidates: &'a mut FxIndexMap<Local, Vec<Local>>,
+    candidates: Vec<(Local, Local)>,
     borrowed: &'a DenseBitSet<Local>,
 }
 
@@ -753,11 +410,9 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
             lhs,
             Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
         )) = &statement.kind
+            && let Some(src) = lhs.as_local()
+            && let Some(dest) = rhs.as_local()
         {
-            let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
-                return;
-            };
-
             // As described at the top of the file, we do not go near things that have
             // their address taken.
             if self.borrowed.contains(src) || self.borrowed.contains(dest) {
@@ -774,13 +429,8 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
                 return;
             }
 
-            // Also, we need to make sure that MIR actually allows the `src` to be removed
-            if is_local_required(src, self.body) {
-                return;
-            }
-
             // We may insert duplicates here, but that's fine
-            self.candidates.entry(src).or_default().push(dest);
+            self.candidates.push((src, dest));
         }
     }
 }
@@ -803,22 +453,162 @@ fn dest_prop_mir_dump<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     points: &DenseLocationMap,
-    live: &SparseIntervalMatrix<Local, PointIndex>,
-    round: usize,
+    live: &SparseIntervalMatrix<RelevantLocal, TwoStepIndex>,
+    relevant: &RelevantLocals,
 ) {
     let locals_live_at = |location| {
-        let location = points.point_from_location(location);
-        live.rows().filter(|&r| live.contains(r, location)).collect::<Vec<_>>()
+        live.rows()
+            .filter(|&r| live.contains(r, location))
+            .map(|rl| relevant.original[rl])
+            .collect::<Vec<_>>()
     };
 
     if let Some(dumper) = MirDumper::new(tcx, "DestinationPropagation-dataflow", body) {
         let extra_data = &|pass_where, w: &mut dyn std::io::Write| {
             if let PassWhere::BeforeLocation(loc) = pass_where {
-                writeln!(w, "        // live: {:?}", locals_live_at(loc))?;
+                let location = TwoStepIndex::new(points, loc, Effect::Before);
+                let live = locals_live_at(location);
+                writeln!(w, "        // before: {:?} => {:?}", location, live)?;
+            }
+            if let PassWhere::AfterLocation(loc) = pass_where {
+                let location = TwoStepIndex::new(points, loc, Effect::After);
+                let live = locals_live_at(location);
+                writeln!(w, "        // after: {:?} => {:?}", location, live)?;
             }
             Ok(())
         };
 
-        dumper.set_disambiguator(&round).set_extra_data(extra_data).dump_mir(body)
+        dumper.set_extra_data(extra_data).dump_mir(body)
     }
 }
+
+#[derive(Copy, Clone, Debug)]
+enum Effect {
+    Before,
+    After,
+}
+
+rustc_index::newtype_index! {
+    /// A reversed `PointIndex` but with the lower bit encoding early/late inside the statement.
+    /// The reversed order allows to use the more efficient `IntervalSet::append` method while we
+    /// iterate on the statements in reverse order.
+    #[orderable]
+    #[debug_format = "TwoStepIndex({})"]
+    struct TwoStepIndex {}
+}
+
+impl TwoStepIndex {
+    fn new(elements: &DenseLocationMap, location: Location, effect: Effect) -> TwoStepIndex {
+        let point = elements.point_from_location(location);
+        let effect = match effect {
+            Effect::Before => 0,
+            Effect::After => 1,
+        };
+        let max_index = 2 * elements.num_points() as u32 - 1;
+        let index = 2 * point.as_u32() + (effect as u32);
+        // Reverse the indexing to use more efficient `IntervalSet::append`.
+        TwoStepIndex::from_u32(max_index - index)
+    }
+}
+
+struct VisitPlacesWith<F>(F);
+
+impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
+where
+    F: FnMut(Place<'tcx>, PlaceContext),
+{
+    fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
+        (self.0)(local.into(), ctxt);
+    }
+
+    fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
+        (self.0)(*place, ctxt);
+        self.visit_projection(place.as_ref(), ctxt, location);
+    }
+}
+
+/// Add points depending on the result of the given dataflow analysis.
+fn save_as_intervals<'tcx>(
+    elements: &DenseLocationMap,
+    body: &Body<'tcx>,
+    relevant: &RelevantLocals,
+    results: Results<DenseBitSet<Local>>,
+) -> SparseIntervalMatrix<RelevantLocal, TwoStepIndex> {
+    let mut values = SparseIntervalMatrix::new(2 * elements.num_points());
+    let mut state = MaybeLiveLocals.bottom_value(body);
+    let reachable_blocks = traversal::reachable_as_bitset(body);
+
+    let two_step_loc = |location, effect| TwoStepIndex::new(elements, location, effect);
+    let append_at =
+        |values: &mut SparseIntervalMatrix<_, _>, state: &DenseBitSet<Local>, twostep| {
+            for (relevant, &original) in relevant.original.iter_enumerated() {
+                if state.contains(original) {
+                    values.append(relevant, twostep);
+                }
+            }
+        };
+
+    // Iterate blocks in decreasing order, to visit locations in decreasing order. This
+    // allows to use the more efficient `append` method to interval sets.
+    for block in body.basic_blocks.indices().rev() {
+        if !reachable_blocks.contains(block) {
+            continue;
+        }
+
+        state.clone_from(&results[block]);
+
+        let block_data = &body.basic_blocks[block];
+        let loc = Location { block, statement_index: block_data.statements.len() };
+
+        let term = block_data.terminator();
+        let mut twostep = two_step_loc(loc, Effect::After);
+        append_at(&mut values, &state, twostep);
+        // Ensure we have a non-zero live range even for dead stores. This is done by marking all
+        // the written-to locals as live in the second half of the statement.
+        // We also ensure that operands read by terminators conflict with writes by that terminator.
+        // For instance a function call may read args after having written to the destination.
+        VisitPlacesWith(|place, ctxt| match DefUse::for_place(place, ctxt) {
+            DefUse::Def | DefUse::Use | DefUse::PartialWrite => {
+                if let Some(relevant) = relevant.shrink[place.local] {
+                    values.insert(relevant, twostep);
+                }
+            }
+            DefUse::NonUse => {}
+        })
+        .visit_terminator(term, loc);
+
+        twostep = TwoStepIndex::from_u32(twostep.as_u32() + 1);
+        debug_assert_eq!(twostep, two_step_loc(loc, Effect::Before));
+        MaybeLiveLocals.apply_early_terminator_effect(&mut state, term, loc);
+        MaybeLiveLocals.apply_primary_terminator_effect(&mut state, term, loc);
+        append_at(&mut values, &state, twostep);
+
+        for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
+            let loc = Location { block, statement_index };
+            twostep = TwoStepIndex::from_u32(twostep.as_u32() + 1);
+            debug_assert_eq!(twostep, two_step_loc(loc, Effect::After));
+            append_at(&mut values, &state, twostep);
+            // Ensure we have a non-zero live range even for dead stores. This is done by marking
+            // all the written-to locals as live in the second half of the statement.
+            VisitPlacesWith(|place, ctxt| match DefUse::for_place(place, ctxt) {
+                DefUse::Def | DefUse::PartialWrite => {
+                    if let Some(relevant) = relevant.shrink[place.local] {
+                        values.insert(relevant, twostep);
+                    }
+                }
+                DefUse::Use | DefUse::NonUse => {}
+            })
+            .visit_statement(stmt, loc);
+
+            twostep = TwoStepIndex::from_u32(twostep.as_u32() + 1);
+            debug_assert_eq!(twostep, two_step_loc(loc, Effect::Before));
+            MaybeLiveLocals.apply_early_statement_effect(&mut state, stmt, loc);
+            MaybeLiveLocals.apply_primary_statement_effect(&mut state, stmt, loc);
+            // ... but reads from operands are marked as live here so they do not conflict with
+            // the all the writes we manually marked as live in the second half of the statement.
+            append_at(&mut values, &state, twostep);
+        }
+    }
+
+    values
+}
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index ad9635aae33..775f5f9a7cf 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -2,6 +2,7 @@ use rustc_errors::codes::*;
 use rustc_errors::{Diag, LintDiagnostic};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::mir::AssertKind;
+use rustc_middle::query::Key;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::{self, Lint};
 use rustc_span::def_id::DefId;
@@ -9,6 +10,46 @@ use rustc_span::{Ident, Span, Symbol};
 
 use crate::fluent_generated as fluent;
 
+/// Emit diagnostic for calls to `#[inline(always)]`-annotated functions with a
+/// `#[target_feature]` attribute where the caller enables a different set of target features.
+pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>(
+    tcx: TyCtxt<'tcx>,
+    call_span: Span,
+    callee_def_id: DefId,
+    caller_def_id: DefId,
+    callee_only: &[&'a str],
+) {
+    let callee = tcx.def_path_str(callee_def_id);
+    let caller = tcx.def_path_str(caller_def_id);
+
+    tcx.node_span_lint(
+        lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
+        tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()),
+        call_span,
+        |lint| {
+            lint.primary_message(format!(
+                "call to `#[inline(always)]`-annotated `{callee}` \
+                requires the same target features to be inlined"
+            ));
+            lint.note("function will not be inlined");
+
+            lint.note(format!(
+                "the following target features are on `{callee}` but missing from `{caller}`: {}",
+                callee_only.join(", ")
+            ));
+            lint.span_note(callee_def_id.default_span(tcx), format!("`{callee}` is defined here"));
+
+            let feats = callee_only.join(",");
+            lint.span_suggestion(
+                tcx.def_span(caller_def_id).shrink_to_lo(),
+                format!("add `#[target_feature]` attribute to `{caller}`"),
+                format!("#[target_feature(enable = \"{feats}\")]\n"),
+                lint::Applicability::MaybeIncorrect,
+            );
+        },
+    );
+}
+
 #[derive(LintDiagnostic)]
 #[diag(mir_transform_unconditional_recursion)]
 #[help]
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 5a13394543b..bf6aa800d20 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -87,6 +87,7 @@
 use std::borrow::Cow;
 
 use either::Either;
+use itertools::Itertools as _;
 use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx};
 use rustc_const_eval::const_eval::DummyMachine;
 use rustc_const_eval::interpret::{
@@ -895,18 +896,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
     fn simplify_aggregate_to_copy(
         &mut self,
-        lhs: &Place<'tcx>,
-        rvalue: &mut Rvalue<'tcx>,
-        location: Location,
-        fields: &[VnIndex],
+        ty: Ty<'tcx>,
         variant_index: VariantIdx,
+        fields: &[VnIndex],
     ) -> Option<VnIndex> {
-        let Some(&first_field) = fields.first() else {
-            return None;
-        };
-        let Value::Projection(copy_from_value, _) = *self.get(first_field) else {
-            return None;
-        };
+        let Some(&first_field) = fields.first() else { return None };
+        let Value::Projection(copy_from_value, _) = *self.get(first_field) else { return None };
+
         // All fields must correspond one-to-one and come from the same aggregate value.
         if fields.iter().enumerate().any(|(index, &v)| {
             if let Value::Projection(pointer, ProjectionElem::Field(from_index, _)) = *self.get(v)
@@ -933,21 +929,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         }
 
-        // Allow introducing places with non-constant offsets, as those are still better than
-        // reconstructing an aggregate.
-        if self.ty(copy_from_local_value) == rvalue.ty(self.local_decls, self.tcx)
-            && let Some(place) = self.try_as_place(copy_from_local_value, location, true)
-        {
-            // Avoid creating `*a = copy (*b)`, as they might be aliases resulting in overlapping assignments.
-            // FIXME: This also avoids any kind of projection, not just derefs. We can add allowed projections.
-            if lhs.as_local().is_some() {
-                self.reused_locals.insert(place.local);
-                *rvalue = Rvalue::Use(Operand::Copy(place));
-            }
-            return Some(copy_from_local_value);
-        }
-
-        None
+        // Both must be variants of the same type.
+        if self.ty(copy_from_local_value) == ty { Some(copy_from_local_value) } else { None }
     }
 
     fn simplify_aggregate(
@@ -1023,20 +1006,27 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         };
 
-        if ty.is_array() && fields.len() > 4 {
-            let first = fields[0];
-            if fields.iter().all(|&v| v == first) {
-                let len = ty::Const::from_target_usize(self.tcx, fields.len().try_into().unwrap());
-                if let Some(op) = self.try_as_operand(first, location) {
-                    *rvalue = Rvalue::Repeat(op, len);
-                }
-                return Some(self.insert(ty, Value::Repeat(first, len)));
+        if ty.is_array()
+            && fields.len() > 4
+            && let Ok(&first) = fields.iter().all_equal_value()
+        {
+            let len = ty::Const::from_target_usize(self.tcx, fields.len().try_into().unwrap());
+            if let Some(op) = self.try_as_operand(first, location) {
+                *rvalue = Rvalue::Repeat(op, len);
             }
+            return Some(self.insert(ty, Value::Repeat(first, len)));
         }
 
-        if let Some(value) =
-            self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index)
-        {
+        if let Some(value) = self.simplify_aggregate_to_copy(ty, variant_index, &fields) {
+            // Allow introducing places with non-constant offsets, as those are still better than
+            // reconstructing an aggregate. But avoid creating `*a = copy (*b)`, as they might be
+            // aliases resulting in overlapping assignments.
+            let allow_complex_projection =
+                lhs.projection[..].iter().all(PlaceElem::is_stable_offset);
+            if let Some(place) = self.try_as_place(value, location, allow_complex_projection) {
+                self.reused_locals.insert(place.local);
+                *rvalue = Rvalue::Use(Operand::Copy(place));
+            }
             return Some(value);
         }
 
@@ -1654,6 +1644,11 @@ impl<'tcx> VnState<'_, 'tcx> {
                 let place =
                     Place { local, projection: self.tcx.mk_place_elems(projection.as_slice()) };
                 return Some(place);
+            } else if projection.last() == Some(&PlaceElem::Deref) {
+                // `Deref` can only be the first projection in a place.
+                // If we are here, we failed to find a local, and we already have a `Deref`.
+                // Trying to add projections will only result in an ill-formed place.
+                return None;
             } else if let Value::Projection(pointer, proj) = *self.get(index)
                 && (allow_complex_projection || proj.is_stable_offset())
                 && let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc)
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 7f9234d1dc8..25a9baffe58 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -2,9 +2,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::UnordSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::limit::Limit;
 use rustc_middle::mir::TerminatorKind;
 use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt, TypeVisitableExt};
-use rustc_session::Limit;
 use rustc_span::sym;
 use tracing::{instrument, trace};
 
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 8f319e64916..1663dfa744f 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -117,6 +117,7 @@ declare_passes! {
     mod add_subtyping_projections : Subtyper;
     mod check_inline : CheckForceInline;
     mod check_call_recursion : CheckCallRecursion, CheckDropRecursion;
+    mod check_inline_always_target_features: CheckInlineAlwaysTargetFeature;
     mod check_alignment : CheckAlignment;
     mod check_enums : CheckEnums;
     mod check_const_item_mutation : CheckConstItemMutation;
@@ -384,6 +385,9 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
             // MIR-level lints.
             &Lint(check_inline::CheckForceInline),
             &Lint(check_call_recursion::CheckCallRecursion),
+            // Check callee's target features match callers target features when
+            // using `#[inline(always)]`
+            &Lint(check_inline_always_target_features::CheckInlineAlwaysTargetFeature),
             &Lint(check_packed_ref::CheckPackedRef),
             &Lint(check_const_item_mutation::CheckConstItemMutation),
             &Lint(function_item_references::FunctionItemReferences),
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
index 794984d2f3e..61c9bbe3123 100644
--- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -2,6 +2,7 @@ use std::cell::RefCell;
 use std::collections::hash_map;
 use std::rc::Rc;
 
+use itertools::Itertools as _;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::Subdiagnostic;
@@ -339,9 +340,9 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
             // Suppose that all BIDs point into the same local,
             // we can remove the this local from the observed drops,
             // so that we can focus our diagnosis more on the others.
-            if candidates.iter().all(|&(_, place)| candidates[0].1.local == place.local) {
+            if let Ok(local) = candidates.iter().map(|&(_, place)| place.local).all_equal_value() {
                 for path_idx in all_locals_dropped.iter() {
-                    if move_data.move_paths[path_idx].place.local == candidates[0].1.local {
+                    if move_data.move_paths[path_idx].place.local == local {
                         to_exclude.insert(path_idx);
                     }
                 }
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 468ef742dfb..75917d23883 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -34,6 +34,7 @@
 //! The normal logic that a program with UB can be changed to do anything does not apply to
 //! pre-"runtime" MIR!
 
+use itertools::Itertools as _;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -288,20 +289,13 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
             return false;
         };
 
-        let first_succ = {
-            if let Some(first_succ) = terminator.successors().next() {
-                if terminator.successors().all(|s| s == first_succ) {
-                    let count = terminator.successors().count();
-                    self.pred_count[first_succ] -= (count - 1) as u32;
-                    first_succ
-                } else {
-                    return false;
-                }
-            } else {
-                return false;
-            }
+        let Ok(first_succ) = terminator.successors().all_equal_value() else {
+            return false;
         };
 
+        let count = terminator.successors().count();
+        self.pred_count[first_succ] -= (count - 1) as u32;
+
         debug!("simplifying branch {:?}", terminator);
         terminator.kind = TerminatorKind::Goto { target: first_succ };
         true
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index cd9a7f4a39d..73c249a3c8c 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -225,6 +225,9 @@ impl SsaVisitor<'_, '_> {
 
 impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> {
     fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
+        if ctxt.may_observe_address() {
+            self.borrowed_locals.insert(local);
+        }
         match ctxt {
             PlaceContext::MutatingUse(MutatingUseContext::Projection)
             | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => bug!(),
@@ -237,7 +240,6 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> {
             PlaceContext::NonMutatingUse(
                 NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow,
             ) => {
-                self.borrowed_locals.insert(local);
                 self.check_dominates(local, loc);
                 self.direct_uses[local] += 1;
             }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index cffeb6f9807..3169f2d4e1a 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -217,6 +217,7 @@ use rustc_hir::attrs::InlineAttr;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::limit::Limit;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
 use rustc_middle::mir::mono::{CollectionMode, InstantiationMode, MonoItem};
@@ -231,7 +232,6 @@ use rustc_middle::ty::{
 };
 use rustc_middle::util::Providers;
 use rustc_middle::{bug, span_bug};
-use rustc_session::Limit;
 use rustc_session::config::{DebugInfo, EntryFnType};
 use rustc_span::source_map::{Spanned, dummy_spanned, respan};
 use rustc_span::{DUMMY_SP, Span};
diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
index 7251ef478c6..0adf1b089b5 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
@@ -1,10 +1,10 @@
 use rustc_abi::Size;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
+use rustc_hir::limit::Limit;
 use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Location, traversal};
 use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable};
-use rustc_session::Limit;
 use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
 use rustc_span::source_map::Spanned;
 use rustc_span::{Ident, Span, sym};
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index da05c49756f..a8f2b4e8db6 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -2,9 +2,8 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::solve::{Goal, QueryInput};
 use rustc_type_ir::{
-    self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalTyVarKind, CanonicalVarKind,
-    Flags, InferCtxtLike, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt,
+    self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, Flags, InferCtxtLike,
+    Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 
 use crate::delegate::SolverDelegate;
@@ -68,6 +67,13 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
     variables: &'a mut Vec<I::GenericArg>,
     var_kinds: Vec<CanonicalVarKind<I>>,
     variable_lookup_table: HashMap<I::GenericArg, usize>,
+    /// Maps each `sub_unification_table_root_var` to the index of the first
+    /// variable which used it.
+    ///
+    /// This means in case two type variables have the same sub relations root,
+    /// we set the `sub_root` of the second variable to the position of the first.
+    /// Otherwise the `sub_root` of each type variable is just its own position.
+    sub_root_lookup_table: HashMap<ty::TyVid, usize>,
     binder_index: ty::DebruijnIndex,
 
     /// We only use the debruijn index during lookup. We don't need to
@@ -89,6 +95,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
             variables,
             variable_lookup_table: Default::default(),
+            sub_root_lookup_table: Default::default(),
             var_kinds: Vec::new(),
             binder_index: ty::INNERMOST,
 
@@ -133,6 +140,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
                         variables: &mut variables,
                         variable_lookup_table: Default::default(),
+                        sub_root_lookup_table: Default::default(),
                         var_kinds: Vec::new(),
                         binder_index: ty::INNERMOST,
 
@@ -140,6 +148,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                     };
                     let param_env = param_env.fold_with(&mut env_canonicalizer);
                     debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
+                    debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
                     CanonicalParamEnvCacheEntry {
                         param_env,
                         variable_lookup_table: env_canonicalizer.variable_lookup_table,
@@ -165,6 +174,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
                 variables,
                 variable_lookup_table: Default::default(),
+                sub_root_lookup_table: Default::default(),
                 var_kinds: Vec::new(),
                 binder_index: ty::INNERMOST,
 
@@ -172,6 +182,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             };
             let param_env = param_env.fold_with(&mut env_canonicalizer);
             debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
+            debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
             (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds)
         }
     }
@@ -200,6 +211,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
             variables,
             variable_lookup_table,
+            sub_root_lookup_table: Default::default(),
             var_kinds,
             binder_index: ty::INNERMOST,
 
@@ -266,6 +278,13 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         ty::BoundVar::from(idx)
     }
 
+    fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
+        let root_vid = self.delegate.sub_unification_table_root_var(vid);
+        let idx =
+            *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
+        ty::BoundVar::from(idx)
+    }
+
     fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) {
         let mut var_kinds = self.var_kinds;
         // See the rustc-dev-guide section about how we deal with universes
@@ -313,18 +332,15 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                         "ty vid should have been resolved fully before canonicalization"
                     );
 
-                    match self.canonicalize_mode {
-                        CanonicalizeMode::Input { .. } => CanonicalVarKind::Ty(
-                            CanonicalTyVarKind::General(ty::UniverseIndex::ROOT),
-                        ),
-                        CanonicalizeMode::Response { .. } => {
-                            CanonicalVarKind::Ty(CanonicalTyVarKind::General(
-                                self.delegate.universe_of_ty(vid).unwrap_or_else(|| {
-                                    panic!("ty var should have been resolved: {t:?}")
-                                }),
-                            ))
-                        }
-                    }
+                    let sub_root = self.get_or_insert_sub_root(vid);
+                    let ui = match self.canonicalize_mode {
+                        CanonicalizeMode::Input { .. } => ty::UniverseIndex::ROOT,
+                        CanonicalizeMode::Response { .. } => self
+                            .delegate
+                            .universe_of_ty(vid)
+                            .unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")),
+                    };
+                    CanonicalVarKind::Ty { ui, sub_root }
                 }
                 ty::IntVar(vid) => {
                     debug_assert_eq!(
@@ -332,7 +348,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                         t,
                         "ty vid should have been resolved fully before canonicalization"
                     );
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
+                    CanonicalVarKind::Int
                 }
                 ty::FloatVar(vid) => {
                     debug_assert_eq!(
@@ -340,7 +356,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                         t,
                         "ty vid should have been resolved fully before canonicalization"
                     );
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
+                    CanonicalVarKind::Float
                 }
                 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
                     panic!("fresh vars not expected in canonicalization")
diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs
index 79219b34e29..b949deb1192 100644
--- a/compiler/rustc_next_trait_solver/src/coherence.rs
+++ b/compiler/rustc_next_trait_solver/src/coherence.rs
@@ -435,7 +435,21 @@ where
                 }
             }
             ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-            ty::Closure(did, ..) | ty::CoroutineClosure(did, ..) | ty::Coroutine(did, ..) => {
+            ty::Closure(did, ..) => {
+                if self.def_id_is_local(did) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::CoroutineClosure(did, ..) => {
+                if self.def_id_is_local(did) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Coroutine(did, ..) => {
                 if self.def_id_is_local(did) {
                     ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
                 } else {
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index 7b932010d49..41c2e5f60ec 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -57,12 +57,14 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
     where
         V: TypeFoldable<Self::Interner>;
 
-    fn instantiate_canonical_var_with_infer(
+    fn instantiate_canonical_var(
         &self,
         kind: ty::CanonicalVarKind<Self::Interner>,
         span: <Self::Interner as Interner>::Span,
+        var_values: &[<Self::Interner as Interner>::GenericArg],
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> <Self::Interner as Interner>::GenericArg;
+
     fn add_item_bounds_for_hidden_type(
         &self,
         def_id: <Self::Interner as Interner>::DefId,
@@ -76,7 +78,7 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
         &self,
         goal_trait_ref: ty::TraitRef<Self::Interner>,
         trait_assoc_def_id: <Self::Interner as Interner>::DefId,
-        impl_def_id: <Self::Interner as Interner>::DefId,
+        impl_def_id: <Self::Interner as Interner>::ImplId,
     ) -> Result<
         Option<<Self::Interner as Interner>::DefId>,
         <Self::Interner as Interner>::ErrorGuaranteed,
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index be7e4dd4cda..e3cf0330b14 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -186,7 +186,7 @@ where
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
-        impl_def_id: I::DefId,
+        impl_def_id: I::ImplId,
     ) -> Result<Candidate<I>, NoSolution>;
 
     /// If the predicate contained an error, we want to avoid emitting unnecessary trait
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 7c5940828da..f6eab286ba7 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -605,7 +605,7 @@ fn coroutine_closure_to_certain_coroutine<I: Interner>(
     cx: I,
     goal_kind: ty::ClosureKind,
     goal_region: I::Region,
-    def_id: I::DefId,
+    def_id: I::CoroutineClosureId,
     args: ty::CoroutineClosureArgs<I>,
     sig: ty::CoroutineClosureSignature<I>,
 ) -> I::Ty {
@@ -629,7 +629,7 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
     cx: I,
     goal_kind: ty::ClosureKind,
     goal_region: I::Region,
-    def_id: I::DefId,
+    def_id: I::CoroutineClosureId,
     args: ty::CoroutineClosureArgs<I>,
     sig: ty::CoroutineClosureSignature<I>,
 ) -> I::Ty {
@@ -664,7 +664,7 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
 pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
     cx: I,
     self_ty: I::Ty,
-) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> {
+) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> {
     match self_ty.kind() {
         ty::FnDef(def_id, args) => {
             let sig = cx.fn_sig(def_id);
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 229345065b1..6646857a136 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -123,7 +123,7 @@ where
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
-        impl_def_id: I::DefId,
+        impl_def_id: I::ImplId,
     ) -> Result<Candidate<I>, NoSolution> {
         let cx = ecx.cx();
 
@@ -152,20 +152,20 @@ where
         }
 
         ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
-            let impl_args = ecx.fresh_args_for_item(impl_def_id);
+            let impl_args = ecx.fresh_args_for_item(impl_def_id.into());
             ecx.record_impl_args(impl_args);
             let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
 
             ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
             let where_clause_bounds = cx
-                .predicates_of(impl_def_id)
+                .predicates_of(impl_def_id.into())
                 .iter_instantiated(cx, impl_args)
                 .map(|pred| goal.with(cx, pred));
             ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
 
             // For this impl to be `const`, we need to check its `[const]` bounds too.
             let const_conditions = cx
-                .const_conditions(impl_def_id)
+                .const_conditions(impl_def_id.into())
                 .iter_instantiated(cx, impl_args)
                 .map(|bound_trait_ref| {
                     goal.with(
@@ -240,7 +240,7 @@ where
             ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output])
         });
         let requirements = cx
-            .const_conditions(def_id)
+            .const_conditions(def_id.into())
             .iter_instantiated(cx, args)
             .map(|trait_ref| {
                 (
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index 6f9f4067384..169832ca5fb 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -16,7 +16,8 @@ use rustc_type_ir::data_structures::HashSet;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::relate::solver_relating::RelateExt;
 use rustc_type_ir::{
-    self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable,
+    self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
+    TypeFoldable,
 };
 use tracing::{debug, instrument, trace};
 
@@ -336,7 +337,16 @@ where
         {
             match result_value.kind() {
                 ty::GenericArgKind::Type(t) => {
-                    if let ty::Bound(debruijn, b) = t.kind() {
+                    // We disable the instantiation guess for inference variables
+                    // and only use it for placeholders. We need to handle the
+                    // `sub_root` of type inference variables which would make this
+                    // more involved. They are also a lot rarer than region variables.
+                    if let ty::Bound(debruijn, b) = t.kind()
+                        && !matches!(
+                            response.variables.get(b.var().as_usize()).unwrap(),
+                            CanonicalVarKind::Ty { .. }
+                        )
+                    {
                         assert_eq!(debruijn, ty::INNERMOST);
                         opt_values[b.var()] = Some(*original_value);
                     }
@@ -355,39 +365,33 @@ where
                 }
             }
         }
-
-        let var_values = delegate.cx().mk_args_from_iter(
-            response.variables.iter().enumerate().map(|(index, var_kind)| {
-                if var_kind.universe() != ty::UniverseIndex::ROOT {
-                    // A variable from inside a binder of the query. While ideally these shouldn't
-                    // exist at all (see the FIXME at the start of this method), we have to deal with
-                    // them for now.
-                    delegate.instantiate_canonical_var_with_infer(var_kind, span, |idx| {
-                        prev_universe + idx.index()
-                    })
-                } else if var_kind.is_existential() {
-                    // As an optimization we sometimes avoid creating a new inference variable here.
-                    //
-                    // All new inference variables we create start out in the current universe of the caller.
-                    // This is conceptually wrong as these inference variables would be able to name
-                    // more placeholders then they should be able to. However the inference variables have
-                    // to "come from somewhere", so by equating them with the original values of the caller
-                    // later on, we pull them down into their correct universe again.
-                    if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
-                        v
-                    } else {
-                        delegate
-                            .instantiate_canonical_var_with_infer(var_kind, span, |_| prev_universe)
-                    }
+        CanonicalVarValues::instantiate(delegate.cx(), response.variables, |var_values, kind| {
+            if kind.universe() != ty::UniverseIndex::ROOT {
+                // A variable from inside a binder of the query. While ideally these shouldn't
+                // exist at all (see the FIXME at the start of this method), we have to deal with
+                // them for now.
+                delegate.instantiate_canonical_var(kind, span, &var_values, |idx| {
+                    prev_universe + idx.index()
+                })
+            } else if kind.is_existential() {
+                // As an optimization we sometimes avoid creating a new inference variable here.
+                //
+                // All new inference variables we create start out in the current universe of the caller.
+                // This is conceptually wrong as these inference variables would be able to name
+                // more placeholders then they should be able to. However the inference variables have
+                // to "come from somewhere", so by equating them with the original values of the caller
+                // later on, we pull them down into their correct universe again.
+                if let Some(v) = opt_values[ty::BoundVar::from_usize(var_values.len())] {
+                    v
                 } else {
-                    // For placeholders which were already part of the input, we simply map this
-                    // universal bound variable back the placeholder of the input.
-                    original_values[var_kind.expect_placeholder_index()]
+                    delegate.instantiate_canonical_var(kind, span, &var_values, |_| prev_universe)
                 }
-            }),
-        );
-
-        CanonicalVarValues { var_values }
+            } else {
+                // For placeholders which were already part of the input, we simply map this
+                // universal bound variable back the placeholder of the input.
+                original_values[kind.expect_placeholder_index()]
+            }
+        })
     }
 
     /// Unify the `original_values` with the `var_values` returned by the canonical query..
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 31106a74527..5cd597d4fe6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -900,6 +900,10 @@ where
             && goal.param_env.visit_with(&mut visitor).is_continue()
     }
 
+    pub(super) fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
+        self.delegate.sub_unify_ty_vids_raw(a, b)
+    }
+
     #[instrument(level = "trace", skip(self, param_env), ret)]
     pub(super) fn eq<T: Relate<I>>(
         &mut self,
@@ -1092,7 +1096,7 @@ where
         &self,
         goal_trait_ref: ty::TraitRef<I>,
         trait_assoc_def_id: I::DefId,
-        impl_def_id: I::DefId,
+        impl_def_id: I::ImplId,
     ) -> Result<Option<I::DefId>, I::ErrorGuaranteed> {
         self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
     }
@@ -1275,7 +1279,7 @@ pub fn evaluate_root_goal_for_proof_tree_raw_provider<
 >(
     cx: I,
     canonical_goal: CanonicalInput<I>,
-) -> (QueryResult<I>, I::ProbeRef) {
+) -> (QueryResult<I>, I::Probe) {
     let mut inspect = inspect::ProofTreeBuilder::new();
     let canonical_result = SearchGraph::<D>::evaluate_root_goal_for_proof_tree(
         cx,
@@ -1284,7 +1288,7 @@ pub fn evaluate_root_goal_for_proof_tree_raw_provider<
         &mut inspect,
     );
     let final_revision = inspect.unwrap();
-    (canonical_result, cx.mk_probe_ref(final_revision))
+    (canonical_result, cx.mk_probe(final_revision))
 }
 
 /// Evaluate a goal to build a proof tree.
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 85f9d852d95..db3460c4ff6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -119,11 +119,15 @@ where
 
     #[instrument(level = "trace", skip(self))]
     fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> {
-        if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
-            self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-        } else {
-            self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
-            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        match (goal.predicate.a.kind(), goal.predicate.b.kind()) {
+            (ty::Infer(ty::TyVar(a_vid)), ty::Infer(ty::TyVar(b_vid))) => {
+                self.sub_unify_ty_vids_raw(a_vid, b_vid);
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+            }
+            _ => {
+                self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            }
         }
     }
 
@@ -414,6 +418,11 @@ pub struct GoalEvaluation<I: Interner> {
     pub has_changed: HasChanged,
     /// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed
     /// before rerunning it.
+    ///
+    /// We knowingly ignore the `sub_root` of our inference variables here. This means we
+    /// may not reevaluate a goal even though a change to the `sub_root` could cause a goal
+    /// to make progress. Tracking them adds additional complexity for an incredibly minor
+    /// type inference improvement. We could look into properly handling this in the future.
     pub stalled_on: Option<GoalStalledOn<I>>,
 }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index cfdf2007391..6e6be829f52 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -5,7 +5,7 @@ mod opaque_types;
 
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
-use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem};
+use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
 use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::{self as ty, Interner, NormalizesTo, PredicateKind, Upcast as _};
 use tracing::instrument;
@@ -193,7 +193,7 @@ where
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, NormalizesTo<I>>,
-        impl_def_id: I::DefId,
+        impl_def_id: I::ImplId,
     ) -> Result<Candidate<I>, NoSolution> {
         let cx = ecx.cx();
 
@@ -217,13 +217,13 @@ where
         };
 
         ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
-            let impl_args = ecx.fresh_args_for_item(impl_def_id);
+            let impl_args = ecx.fresh_args_for_item(impl_def_id.into());
             let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
 
             ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
 
             let where_clause_bounds = cx
-                .predicates_of(impl_def_id)
+                .predicates_of(impl_def_id.into())
                 .iter_instantiated(cx, impl_args)
                 .map(|pred| goal.with(cx, pred));
             ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
@@ -824,10 +824,10 @@ where
             // coroutine yield ty `Poll<Option<I>>`.
             let wrapped_expected_ty = Ty::new_adt(
                 cx,
-                cx.adt_def(cx.require_lang_item(SolverLangItem::Poll)),
+                cx.adt_def(cx.require_adt_lang_item(SolverAdtLangItem::Poll)),
                 cx.mk_args(&[Ty::new_adt(
                     cx,
-                    cx.adt_def(cx.require_lang_item(SolverLangItem::Option)),
+                    cx.adt_def(cx.require_adt_lang_item(SolverAdtLangItem::Option)),
                     cx.mk_args(&[expected_ty.into()]),
                 )
                 .into()]),
@@ -979,7 +979,7 @@ where
     fn translate_args(
         &mut self,
         goal: Goal<I, ty::NormalizesTo<I>>,
-        impl_def_id: I::DefId,
+        impl_def_id: I::ImplId,
         impl_args: I::GenericArgs,
         impl_trait_ref: rustc_type_ir::TraitRef<I>,
         target_container_def_id: I::DefId,
@@ -988,14 +988,15 @@ where
         Ok(if target_container_def_id == impl_trait_ref.def_id.into() {
             // Default value from the trait definition. No need to rebase.
             goal.predicate.alias.args
-        } else if target_container_def_id == impl_def_id {
+        } else if target_container_def_id == impl_def_id.into() {
             // Same impl, no need to fully translate, just a rebase from
             // the trait is sufficient.
             goal.predicate.alias.args.rebase_onto(cx, impl_trait_ref.def_id.into(), impl_args)
         } else {
             let target_args = self.fresh_args_for_item(target_container_def_id);
-            let target_trait_ref =
-                cx.impl_trait_ref(target_container_def_id).instantiate(cx, target_args);
+            let target_trait_ref = cx
+                .impl_trait_ref(target_container_def_id.try_into().unwrap())
+                .instantiate(cx, target_args);
             // Relate source impl to target impl by equating trait refs.
             self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
             // Also add predicates since they may be needed to constrain the
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index cdcfebf2909..3e720a47f32 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -54,7 +54,7 @@ where
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, TraitPredicate<I>>,
-        impl_def_id: I::DefId,
+        impl_def_id: I::ImplId,
     ) -> Result<Candidate<I>, NoSolution> {
         let cx = ecx.cx();
 
@@ -91,13 +91,13 @@ where
         };
 
         ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
-            let impl_args = ecx.fresh_args_for_item(impl_def_id);
+            let impl_args = ecx.fresh_args_for_item(impl_def_id.into());
             ecx.record_impl_args(impl_args);
             let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
 
             ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
             let where_clause_bounds = cx
-                .predicates_of(impl_def_id)
+                .predicates_of(impl_def_id.into())
                 .iter_instantiated(cx, impl_args)
                 .map(|pred| goal.with(cx, pred));
             ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 4ca2f57bd87..77dd313d9b8 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -58,7 +58,7 @@ parse_async_use_order_incorrect = the order of `use` and `async` is incorrect
 parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
     .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
 
-parse_at_in_struct_pattern = Unexpected `@` in struct pattern
+parse_at_in_struct_pattern = unexpected `@` in struct pattern
     .note = struct patterns use `field: pattern` syntax to bind to fields
     .help = consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended
 
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index e3bd6a9a327..f5f081efc49 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -44,19 +44,44 @@ pub(crate) struct UnmatchedDelim {
     pub candidate_span: Option<Span>,
 }
 
+/// Which tokens should be stripped before lexing the tokens.
+pub(crate) enum StripTokens {
+    /// Strip both shebang and frontmatter.
+    ShebangAndFrontmatter,
+    /// Strip the shebang but not frontmatter.
+    ///
+    /// That means that char sequences looking like frontmatter are simply
+    /// interpreted as regular Rust lexemes.
+    Shebang,
+    /// Strip nothing.
+    ///
+    /// In other words, char sequences looking like a shebang or frontmatter
+    /// are simply interpreted as regular Rust lexemes.
+    Nothing,
+}
+
 pub(crate) fn lex_token_trees<'psess, 'src>(
     psess: &'psess ParseSess,
     mut src: &'src str,
     mut start_pos: BytePos,
     override_span: Option<Span>,
-    frontmatter_allowed: FrontmatterAllowed,
+    strip_tokens: StripTokens,
 ) -> Result<TokenStream, Vec<Diag<'psess>>> {
-    // Skip `#!`, if present.
-    if let Some(shebang_len) = rustc_lexer::strip_shebang(src) {
-        src = &src[shebang_len..];
-        start_pos = start_pos + BytePos::from_usize(shebang_len);
+    match strip_tokens {
+        StripTokens::Shebang | StripTokens::ShebangAndFrontmatter => {
+            if let Some(shebang_len) = rustc_lexer::strip_shebang(src) {
+                src = &src[shebang_len..];
+                start_pos = start_pos + BytePos::from_usize(shebang_len);
+            }
+        }
+        StripTokens::Nothing => {}
     }
 
+    let frontmatter_allowed = match strip_tokens {
+        StripTokens::ShebangAndFrontmatter => FrontmatterAllowed::Yes,
+        StripTokens::Shebang | StripTokens::Nothing => FrontmatterAllowed::No,
+    };
+
     let cursor = Cursor::new(src, frontmatter_allowed);
     let mut lexer = Lexer {
         psess,
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 197333d942d..d8792d7af4c 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -21,7 +21,6 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{AttrItem, Attribute, MetaItemInner, token};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
-use rustc_lexer::FrontmatterAllowed;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{FileName, SourceFile, Span};
@@ -34,6 +33,8 @@ pub mod parser;
 use parser::Parser;
 use rustc_ast::token::Delimiter;
 
+use crate::lexer::StripTokens;
+
 pub mod lexer;
 
 mod errors;
@@ -62,7 +63,20 @@ pub fn new_parser_from_source_str(
     source: String,
 ) -> Result<Parser<'_>, Vec<Diag<'_>>> {
     let source_file = psess.source_map().new_source_file(name, source);
-    new_parser_from_source_file(psess, source_file)
+    new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter)
+}
+
+/// Creates a new parser from a simple (no shebang, no frontmatter) source string.
+///
+/// On failure, the errors must be consumed via `unwrap_or_emit_fatal`, `emit`, `cancel`,
+/// etc., otherwise a panic will occur when they are dropped.
+pub fn new_parser_from_simple_source_str(
+    psess: &ParseSess,
+    name: FileName,
+    source: String,
+) -> Result<Parser<'_>, Vec<Diag<'_>>> {
+    let source_file = psess.source_map().new_source_file(name, source);
+    new_parser_from_source_file(psess, source_file, StripTokens::Nothing)
 }
 
 /// Creates a new parser from a filename. On failure, the errors must be consumed via
@@ -96,7 +110,7 @@ pub fn new_parser_from_file<'a>(
         }
         err.emit();
     });
-    new_parser_from_source_file(psess, source_file)
+    new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter)
 }
 
 pub fn utf8_error<E: EmissionGuarantee>(
@@ -147,9 +161,10 @@ pub fn utf8_error<E: EmissionGuarantee>(
 fn new_parser_from_source_file(
     psess: &ParseSess,
     source_file: Arc<SourceFile>,
+    strip_tokens: StripTokens,
 ) -> Result<Parser<'_>, Vec<Diag<'_>>> {
     let end_pos = source_file.end_position();
-    let stream = source_file_to_stream(psess, source_file, None, FrontmatterAllowed::Yes)?;
+    let stream = source_file_to_stream(psess, source_file, None, strip_tokens)?;
     let mut parser = Parser::new(psess, stream, None);
     if parser.token == token::Eof {
         parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None);
@@ -165,8 +180,8 @@ pub fn source_str_to_stream(
 ) -> Result<TokenStream, Vec<Diag<'_>>> {
     let source_file = psess.source_map().new_source_file(name, source);
     // used mainly for `proc_macro` and the likes, not for our parsing purposes, so don't parse
-    // frontmatters as frontmatters.
-    source_file_to_stream(psess, source_file, override_span, FrontmatterAllowed::No)
+    // frontmatters as frontmatters, but for compatibility reason still strip the shebang
+    source_file_to_stream(psess, source_file, override_span, StripTokens::Shebang)
 }
 
 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
@@ -175,7 +190,7 @@ fn source_file_to_stream<'psess>(
     psess: &'psess ParseSess,
     source_file: Arc<SourceFile>,
     override_span: Option<Span>,
-    frontmatter_allowed: FrontmatterAllowed,
+    strip_tokens: StripTokens,
 ) -> Result<TokenStream, Vec<Diag<'psess>>> {
     let src = source_file.src.as_ref().unwrap_or_else(|| {
         psess.dcx().bug(format!(
@@ -184,13 +199,7 @@ fn source_file_to_stream<'psess>(
         ));
     });
 
-    lexer::lex_token_trees(
-        psess,
-        src.as_str(),
-        source_file.start_pos,
-        override_span,
-        frontmatter_allowed,
-    )
+    lexer::lex_token_trees(psess, src.as_str(), source_file.start_pos, override_span, strip_tokens)
 }
 
 /// Runs the given subparser `f` on the tokens of the given `attr`'s item.
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 9b09cbba7af..4c02547357e 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2742,7 +2742,7 @@ impl<'a> Parser<'a> {
     /// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
     /// i.e. the same span we use to later decide whether the drop behaviour should be that of
     /// edition `..=2021` or that of `2024..`.
-    // Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions.
+    // Public to use it for custom `if` expressions in rustfmt forks like https://github.com/tucant/rustfmt
     pub fn parse_expr_cond(
         &mut self,
         let_chains_policy: LetChainsPolicy,
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 15598f32429..3bbca622975 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -22,6 +22,8 @@ use std::{fmt, mem, slice};
 use attr_wrapper::{AttrWrapper, UsePreAttrPos};
 pub use diagnostics::AttemptLocalParseRecovery;
 pub(crate) use expr::ForbiddenLetReason;
+// Public to use it for custom `if` expressions in rustfmt forks like https://github.com/tucant/rustfmt
+pub use expr::LetChainsPolicy;
 pub(crate) use item::{FnContext, FnParseMode};
 pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
 pub use path::PathStyle;
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 498d9a405fa..afd08319738 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -687,6 +687,7 @@ passes_unused_var_maybe_capture_ref = unused variable: `{$name}`
 
 passes_unused_var_remove_field = unused variable: `{$name}`
 passes_unused_var_remove_field_suggestion = try removing the field
+passes_unused_var_typo = you might have meant to pattern match on the similarly named {$kind} `{$item_name}`
 
 passes_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2cd4830b5d9..487bdd2a888 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -270,6 +270,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::Linkage(..)
                     | AttributeKind::MustUse { .. }
                     | AttributeKind::CrateName { .. }
+                    | AttributeKind::RecursionLimit { .. }
+                    | AttributeKind::MoveSizeLimit { .. }
+                    | AttributeKind::TypeLengthLimit { .. }
+                    | AttributeKind::PatternComplexityLimit { .. }
                 ) => { /* do nothing  */ }
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 680e2a26d84..23dcabef1a1 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1367,6 +1367,22 @@ pub(crate) struct UnusedVarRemoveFieldSugg {
 #[note]
 pub(crate) struct UnusedVarAssignedOnly {
     pub name: String,
+    #[subdiagnostic]
+    pub typo: Option<PatternTypo>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    passes_unused_var_typo,
+    style = "verbose",
+    applicability = "machine-applicable"
+)]
+pub(crate) struct PatternTypo {
+    #[suggestion_part(code = "{code}")]
+    pub span: Span,
+    pub code: String,
+    pub item_name: String,
+    pub kind: String,
 }
 
 #[derive(LintDiagnostic)]
@@ -1434,6 +1450,8 @@ pub(crate) struct UnusedVariableTryPrefix {
     #[subdiagnostic]
     pub sugg: UnusedVariableSugg,
     pub name: String,
+    #[subdiagnostic]
+    pub typo: Option<PatternTypo>,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index ae16a51bc69..1b2ffb5b3db 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -95,8 +95,10 @@ use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, find_attr};
 use rustc_index::IndexVec;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
 use rustc_session::lint;
+use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{BytePos, Span, Symbol};
 use tracing::{debug, instrument};
 
@@ -1688,6 +1690,51 @@ impl<'tcx> Liveness<'_, 'tcx> {
             let is_assigned =
                 if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) };
 
+            let mut typo = None;
+            for (hir_id, _, span) in &hir_ids_and_spans {
+                let ty = self.typeck_results.node_type(*hir_id);
+                if let ty::Adt(adt, _) = ty.peel_refs().kind() {
+                    let name = Symbol::intern(&name);
+                    let adt_def = self.ir.tcx.adt_def(adt.did());
+                    let variant_names: Vec<_> = adt_def
+                        .variants()
+                        .iter()
+                        .filter(|v| matches!(v.ctor, Some((CtorKind::Const, _))))
+                        .map(|v| v.name)
+                        .collect();
+                    if let Some(name) = find_best_match_for_name(&variant_names, name, None)
+                        && let Some(variant) = adt_def.variants().iter().find(|v| {
+                            v.name == name && matches!(v.ctor, Some((CtorKind::Const, _)))
+                        })
+                    {
+                        typo = Some(errors::PatternTypo {
+                            span: *span,
+                            code: with_no_trimmed_paths!(self.ir.tcx.def_path_str(variant.def_id)),
+                            kind: self.ir.tcx.def_descr(variant.def_id).to_string(),
+                            item_name: variant.name.to_string(),
+                        });
+                    }
+                }
+            }
+            if typo.is_none() {
+                for (hir_id, _, span) in &hir_ids_and_spans {
+                    let ty = self.typeck_results.node_type(*hir_id);
+                    // Look for consts of the same type with similar names as well, not just unit
+                    // structs and variants.
+                    for def_id in self.ir.tcx.hir_body_owners() {
+                        if let DefKind::Const = self.ir.tcx.def_kind(def_id)
+                            && self.ir.tcx.type_of(def_id).instantiate_identity() == ty
+                        {
+                            typo = Some(errors::PatternTypo {
+                                span: *span,
+                                code: with_no_trimmed_paths!(self.ir.tcx.def_path_str(def_id)),
+                                kind: "constant".to_string(),
+                                item_name: self.ir.tcx.item_name(def_id).to_string(),
+                            });
+                        }
+                    }
+                }
+            }
             if is_assigned {
                 self.ir.tcx.emit_node_span_lint(
                     lint::builtin::UNUSED_VARIABLES,
@@ -1696,7 +1743,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
                         .into_iter()
                         .map(|(_, _, ident_span)| ident_span)
                         .collect::<Vec<_>>(),
-                    errors::UnusedVarAssignedOnly { name },
+                    errors::UnusedVarAssignedOnly { name, typo },
                 )
             } else if can_remove {
                 let spans = hir_ids_and_spans
@@ -1788,6 +1835,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
                             name,
                             sugg,
                             string_interp: suggestions,
+                            typo,
                         },
                     );
                 }
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index e5cceacf15d..257785b10c8 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -13,7 +13,6 @@ rustc_index = { path = "../rustc_index" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
-rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 306d4dbc4b4..e499e08c82b 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -58,7 +58,7 @@ impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDA
     for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
 {
     fn clone(&self) -> Self {
-        DynamicConfig { dynamic: self.dynamic }
+        *self
     }
 }
 
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 55549cba737..4e601a6c594 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -9,6 +9,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{DynSend, DynSync};
 use rustc_data_structures::unord::UnordMap;
 use rustc_hashes::Hash64;
+use rustc_hir::limit::Limit;
 use rustc_index::Idx;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{
@@ -31,7 +32,6 @@ use rustc_query_system::query::{
 };
 use rustc_query_system::{QueryOverflow, QueryOverflowNote};
 use rustc_serialize::{Decodable, Encodable};
-use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
 
 use crate::QueryConfigRestored;
diff --git a/compiler/rustc_query_system/messages.ftl b/compiler/rustc_query_system/messages.ftl
index f48dc60afa0..f686608034c 100644
--- a/compiler/rustc_query_system/messages.ftl
+++ b/compiler/rustc_query_system/messages.ftl
@@ -18,8 +18,8 @@ query_system_cycle_usage = cycle used when {$usage}
 query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node}
     .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile
 
-query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information
-query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information
+query_system_increment_compilation_note1 = please follow the instructions below to create a bug report with the provided information
+query_system_increment_compilation_note2 = see <https://github.com/rust-lang/rust/issues/84970> for more information
 
 query_system_overflow_note = query depth increased by {$depth} when {$desc}
 
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
index 5108ecaeea3..2778b24e774 100644
--- a/compiler/rustc_query_system/src/error.rs
+++ b/compiler/rustc_query_system/src/error.rs
@@ -1,6 +1,6 @@
 use rustc_errors::codes::*;
+use rustc_hir::limit::Limit;
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_session::Limit;
 use rustc_span::{Span, Symbol};
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 47280a93677..0e566e20a12 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -470,6 +470,8 @@ resolve_variable_bound_with_different_mode =
     .label = bound in different ways
     .first_binding_span = first binding
 
+resolve_variable_is_a_typo = you might have meant to use the similarly named previously used binding `{$typo}`
+
 resolve_variable_is_not_bound_in_all_patterns =
     variable `{$name}` is not bound in all patterns
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 5dfc4292a38..689e713ef46 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1,3 +1,4 @@
+use itertools::Itertools as _;
 use rustc_ast::visit::{self, Visitor};
 use rustc_ast::{
     self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents,
@@ -661,8 +662,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
                 let BindingError { name, target, origin, could_be_path } = binding_error;
 
-                let target_sp = target.iter().copied().collect::<Vec<_>>();
-                let origin_sp = origin.iter().copied().collect::<Vec<_>>();
+                let mut target_sp = target.iter().map(|pat| pat.span).collect::<Vec<_>>();
+                target_sp.sort();
+                target_sp.dedup();
+                let mut origin_sp = origin.iter().map(|(span, _)| *span).collect::<Vec<_>>();
+                origin_sp.sort();
+                origin_sp.dedup();
 
                 let msp = MultiSpan::from_spans(target_sp.clone());
                 let mut err = self
@@ -671,8 +676,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 for sp in target_sp {
                     err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name });
                 }
-                for sp in origin_sp {
-                    err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp });
+                for sp in &origin_sp {
+                    err.subdiagnostic(errors::VariableNotInAllPatterns { span: *sp });
+                }
+                let mut suggested_typo = false;
+                if !target.iter().all(|pat| matches!(pat.kind, ast::PatKind::Ident(..)))
+                    && !origin.iter().all(|(_, pat)| matches!(pat.kind, ast::PatKind::Ident(..)))
+                {
+                    // The check above is so that when we encounter `match foo { (a | b) => {} }`,
+                    // we don't suggest `(a | a) => {}`, which would never be what the user wants.
+                    let mut target_visitor = BindingVisitor::default();
+                    for pat in &target {
+                        target_visitor.visit_pat(pat);
+                    }
+                    target_visitor.identifiers.sort();
+                    target_visitor.identifiers.dedup();
+                    let mut origin_visitor = BindingVisitor::default();
+                    for (_, pat) in &origin {
+                        origin_visitor.visit_pat(pat);
+                    }
+                    origin_visitor.identifiers.sort();
+                    origin_visitor.identifiers.dedup();
+                    // Find if the binding could have been a typo
+                    if let Some(typo) =
+                        find_best_match_for_name(&target_visitor.identifiers, name.name, None)
+                        && !origin_visitor.identifiers.contains(&typo)
+                    {
+                        err.subdiagnostic(errors::PatternBindingTypo { spans: origin_sp, typo });
+                        suggested_typo = true;
+                    }
                 }
                 if could_be_path {
                     let import_suggestions = self.lookup_import_candidates(
@@ -693,10 +725,86 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         },
                     );
 
-                    if import_suggestions.is_empty() {
+                    if import_suggestions.is_empty() && !suggested_typo {
+                        let kinds = [
+                            DefKind::Ctor(CtorOf::Variant, CtorKind::Const),
+                            DefKind::Ctor(CtorOf::Struct, CtorKind::Const),
+                            DefKind::Const,
+                            DefKind::AssocConst,
+                        ];
+                        let mut local_names = vec![];
+                        self.add_module_candidates(
+                            parent_scope.module,
+                            &mut local_names,
+                            &|res| matches!(res, Res::Def(_, _)),
+                            None,
+                        );
+                        let local_names: FxHashSet<_> = local_names
+                            .into_iter()
+                            .filter_map(|s| match s.res {
+                                Res::Def(_, def_id) => Some(def_id),
+                                _ => None,
+                            })
+                            .collect();
+
+                        let mut local_suggestions = vec![];
+                        let mut suggestions = vec![];
+                        for kind in kinds {
+                            if let Some(suggestion) = self.early_lookup_typo_candidate(
+                                ScopeSet::All(Namespace::ValueNS),
+                                &parent_scope,
+                                name,
+                                &|res: Res| match res {
+                                    Res::Def(k, _) => k == kind,
+                                    _ => false,
+                                },
+                            ) && let Res::Def(kind, mut def_id) = suggestion.res
+                            {
+                                if let DefKind::Ctor(_, _) = kind {
+                                    def_id = self.tcx.parent(def_id);
+                                }
+                                let kind = kind.descr(def_id);
+                                if local_names.contains(&def_id) {
+                                    // The item is available in the current scope. Very likely to
+                                    // be a typo. Don't use the full path.
+                                    local_suggestions.push((
+                                        suggestion.candidate,
+                                        suggestion.candidate.to_string(),
+                                        kind,
+                                    ));
+                                } else {
+                                    suggestions.push((
+                                        suggestion.candidate,
+                                        self.def_path_str(def_id),
+                                        kind,
+                                    ));
+                                }
+                            }
+                        }
+                        let suggestions = if !local_suggestions.is_empty() {
+                            // There is at least one item available in the current scope that is a
+                            // likely typo. We only show those.
+                            local_suggestions
+                        } else {
+                            suggestions
+                        };
+                        for (name, sugg, kind) in suggestions {
+                            err.span_suggestion_verbose(
+                                span,
+                                format!(
+                                    "you might have meant to use the similarly named {kind} `{name}`",
+                                ),
+                                sugg,
+                                Applicability::MaybeIncorrect,
+                            );
+                            suggested_typo = true;
+                        }
+                    }
+                    if import_suggestions.is_empty() && !suggested_typo {
                         let help_msg = format!(
-                            "if you meant to match on a variant or a `const` item, consider \
-                             making the path in the pattern qualified: `path::to::ModOrType::{name}`",
+                            "if you meant to match on a unit struct, unit variant or a `const` \
+                             item, consider making the path in the pattern qualified: \
+                             `path::to::ModOrType::{name}`",
                         );
                         err.span_help(span, help_msg);
                     }
@@ -1016,6 +1124,39 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         .emit()
     }
 
+    fn def_path_str(&self, mut def_id: DefId) -> String {
+        // We can't use `def_path_str` in resolve.
+        let mut path = vec![def_id];
+        while let Some(parent) = self.tcx.opt_parent(def_id) {
+            def_id = parent;
+            path.push(def_id);
+            if def_id.is_top_level_module() {
+                break;
+            }
+        }
+        // We will only suggest importing directly if it is accessible through that path.
+        path.into_iter()
+            .rev()
+            .map(|def_id| {
+                self.tcx
+                    .opt_item_name(def_id)
+                    .map(|name| {
+                        match (
+                            def_id.is_top_level_module(),
+                            def_id.is_local(),
+                            self.tcx.sess.edition(),
+                        ) {
+                            (true, true, Edition::Edition2015) => String::new(),
+                            (true, true, _) => kw::Crate.to_string(),
+                            (true, false, _) | (false, _, _) => name.to_string(),
+                        }
+                    })
+                    .unwrap_or_else(|| "_".to_string())
+            })
+            .collect::<Vec<String>>()
+            .join("::")
+    }
+
     pub(crate) fn add_scope_set_candidates(
         &mut self,
         suggestions: &mut Vec<TypoSuggestion>,
@@ -1846,7 +1987,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let extern_prelude_ambiguity = || {
             self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| {
                 entry.item_binding.map(|(b, _)| b) == Some(b1)
-                    && entry.flag_binding.as_ref().and_then(|pb| pb.get().binding()) == Some(b2)
+                    && entry.flag_binding.as_ref().and_then(|pb| pb.get().0.binding()) == Some(b2)
             })
         };
         let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
@@ -3329,16 +3470,11 @@ fn show_candidates(
                 err.note(note.to_string());
             }
         } else {
-            let (_, descr_first, _, _, _) = &inaccessible_path_strings[0];
-            let descr = if inaccessible_path_strings
+            let descr = inaccessible_path_strings
                 .iter()
-                .skip(1)
-                .all(|(_, descr, _, _, _)| descr == descr_first)
-            {
-                descr_first
-            } else {
-                "item"
-            };
+                .map(|&(_, descr, _, _, _)| descr)
+                .all_equal_value()
+                .unwrap_or("item");
             let plural_descr =
                 if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
 
@@ -3396,7 +3532,7 @@ impl UsePlacementFinder {
     }
 }
 
-impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     fn visit_crate(&mut self, c: &Crate) {
         if self.target_module == CRATE_NODE_ID {
             let inject = c.spans.inject_use_span;
@@ -3424,6 +3560,22 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
     }
 }
 
+#[derive(Default)]
+struct BindingVisitor {
+    identifiers: Vec<Symbol>,
+    spans: FxHashMap<Symbol, Vec<Span>>,
+}
+
+impl<'tcx> Visitor<'tcx> for BindingVisitor {
+    fn visit_pat(&mut self, pat: &ast::Pat) {
+        if let ast::PatKind::Ident(_, ident, _) = pat.kind {
+            self.identifiers.push(ident.name);
+            self.spans.entry(ident.name).or_default().push(ident.span);
+        }
+        visit::walk_pat(self, pat);
+    }
+}
+
 fn search_for_any_use_in_items(items: &[Box<ast::Item>]) -> Option<Span> {
     for item in items {
         if let ItemKind::Use(..) = item.kind
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 63d6fa23a14..72be94e58db 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -986,6 +986,18 @@ pub(crate) struct VariableNotInAllPatterns {
     pub(crate) span: Span,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    resolve_variable_is_a_typo,
+    applicability = "maybe-incorrect",
+    style = "verbose"
+)]
+pub(crate) struct PatternBindingTypo {
+    #[suggestion_part(code = "{typo}")]
+    pub(crate) spans: Vec<Span>,
+    pub(crate) typo: Symbol,
+}
+
 #[derive(Diagnostic)]
 #[diag(resolve_name_defined_multiple_time)]
 #[note]
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 6a12fafcb1e..521fef2b9d4 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -8,7 +8,6 @@
 
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
-use std::collections::BTreeSet;
 use std::collections::hash_map::Entry;
 use std::mem::{replace, swap, take};
 
@@ -3682,31 +3681,30 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         // 2) Record any missing bindings or binding mode inconsistencies.
         for (map_outer, pat_outer) in not_never_pats.iter() {
             // Check against all arms except for the same pattern which is always self-consistent.
-            let inners = not_never_pats
-                .iter()
-                .filter(|(_, pat)| pat.id != pat_outer.id)
-                .flat_map(|(map, _)| map);
-
-            for (&name, binding_inner) in inners {
-                match map_outer.get(&name) {
-                    None => {
-                        // The inner binding is missing in the outer.
-                        let binding_error =
-                            missing_vars.entry(name).or_insert_with(|| BindingError {
-                                name,
-                                origin: BTreeSet::new(),
-                                target: BTreeSet::new(),
-                                could_be_path: name.as_str().starts_with(char::is_uppercase),
-                            });
-                        binding_error.origin.insert(binding_inner.span);
-                        binding_error.target.insert(pat_outer.span);
-                    }
-                    Some(binding_outer) => {
-                        if binding_outer.annotation != binding_inner.annotation {
-                            // The binding modes in the outer and inner bindings differ.
-                            inconsistent_vars
-                                .entry(name)
-                                .or_insert((binding_inner.span, binding_outer.span));
+            let inners = not_never_pats.iter().filter(|(_, pat)| pat.id != pat_outer.id);
+
+            for (map, pat) in inners {
+                for (&name, binding_inner) in map {
+                    match map_outer.get(&name) {
+                        None => {
+                            // The inner binding is missing in the outer.
+                            let binding_error =
+                                missing_vars.entry(name).or_insert_with(|| BindingError {
+                                    name,
+                                    origin: Default::default(),
+                                    target: Default::default(),
+                                    could_be_path: name.as_str().starts_with(char::is_uppercase),
+                                });
+                            binding_error.origin.push((binding_inner.span, (***pat).clone()));
+                            binding_error.target.push((***pat_outer).clone());
+                        }
+                        Some(binding_outer) => {
+                            if binding_outer.annotation != binding_inner.annotation {
+                                // The binding modes in the outer and inner bindings differ.
+                                inconsistent_vars
+                                    .entry(name)
+                                    .or_insert((binding_inner.span, binding_outer.span));
+                            }
                         }
                     }
                 }
@@ -3719,7 +3717,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 v.could_be_path = false;
             }
             self.report_error(
-                *v.origin.iter().next().unwrap(),
+                v.origin.iter().next().unwrap().0,
                 ResolutionError::VariableNotBoundInPattern(v, self.parent_scope),
             );
         }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 80b2095d8cc..9e3c0938836 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -3099,7 +3099,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                 |err, _, span, message, suggestion, span_suggs| {
                     err.multipart_suggestion_verbose(
                         message,
-                        std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
+                        std::iter::once((span, suggestion)).chain(span_suggs).collect(),
                         Applicability::MaybeIncorrect,
                     );
                     true
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9674c0356c2..8b185ce7ef2 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -230,8 +230,8 @@ enum Used {
 #[derive(Debug)]
 struct BindingError {
     name: Ident,
-    origin: BTreeSet<Span>,
-    target: BTreeSet<Span>,
+    origin: Vec<(Span, ast::Pat)>,
+    target: Vec<ast::Pat>,
     could_be_path: bool,
 }
 
@@ -1031,7 +1031,7 @@ struct ExternPreludeEntry<'ra> {
     /// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming.
     item_binding: Option<(NameBinding<'ra>, /* introduced by item */ bool)>,
     /// Binding from an `--extern` flag, lazily populated on first use.
-    flag_binding: Option<Cell<PendingBinding<'ra>>>,
+    flag_binding: Option<Cell<(PendingBinding<'ra>, /* finalized */ bool)>>,
 }
 
 impl ExternPreludeEntry<'_> {
@@ -1042,7 +1042,7 @@ impl ExternPreludeEntry<'_> {
     fn flag() -> Self {
         ExternPreludeEntry {
             item_binding: None,
-            flag_binding: Some(Cell::new(PendingBinding::Pending)),
+            flag_binding: Some(Cell::new((PendingBinding::Pending, false))),
         }
     }
 }
@@ -2245,14 +2245,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> {
         let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident));
         entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| {
-            let binding = match flag_binding.get() {
+            let (pending_binding, finalized) = flag_binding.get();
+            let binding = match pending_binding {
                 PendingBinding::Ready(binding) => {
-                    if finalize {
+                    if finalize && !finalized {
                         self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
                     }
                     binding
                 }
                 PendingBinding::Pending => {
+                    debug_assert!(!finalized);
                     let crate_id = if finalize {
                         self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
                     } else {
@@ -2264,7 +2266,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     })
                 }
             };
-            flag_binding.set(PendingBinding::Ready(binding));
+            flag_binding.set((PendingBinding::Ready(binding), finalize || finalized));
             binding.or_else(|| finalize.then_some(self.dummy_binding))
         })
     }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 6d5be2d92cd..69facde6936 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -83,10 +83,77 @@ pub struct TargetModifier {
     pub value_name: String,
 }
 
+mod target_modifier_consistency_check {
+    use super::*;
+    pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool {
+        let mut lparsed: SanitizerSet = Default::default();
+        let lval = if l.value_name.is_empty() { None } else { Some(l.value_name.as_str()) };
+        parse::parse_sanitizers(&mut lparsed, lval);
+
+        let mut rparsed: SanitizerSet = Default::default();
+        let rval = r.filter(|v| !v.value_name.is_empty()).map(|v| v.value_name.as_str());
+        parse::parse_sanitizers(&mut rparsed, rval);
+
+        // Some sanitizers need to be target modifiers, and some do not.
+        // For now, we should mark all sanitizers as target modifiers except for these:
+        // AddressSanitizer, LeakSanitizer
+        let tmod_sanitizers = SanitizerSet::MEMORY
+            | SanitizerSet::THREAD
+            | SanitizerSet::HWADDRESS
+            | SanitizerSet::CFI
+            | SanitizerSet::MEMTAG
+            | SanitizerSet::SHADOWCALLSTACK
+            | SanitizerSet::KCFI
+            | SanitizerSet::KERNELADDRESS
+            | SanitizerSet::SAFESTACK
+            | SanitizerSet::DATAFLOW;
+
+        lparsed & tmod_sanitizers == rparsed & tmod_sanitizers
+    }
+    pub(super) fn sanitizer_cfi_normalize_integers(
+        opts: &Options,
+        l: &TargetModifier,
+        r: Option<&TargetModifier>,
+    ) -> bool {
+        // For kCFI, the helper flag -Zsanitizer-cfi-normalize-integers should also be a target modifier
+        if opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI) {
+            if let Some(r) = r {
+                return l.extend().tech_value == r.extend().tech_value;
+            } else {
+                return false;
+            }
+        }
+        true
+    }
+}
+
 impl TargetModifier {
     pub fn extend(&self) -> ExtendedTargetModifierInfo {
         self.opt.reparse(&self.value_name)
     }
+    // Custom consistency check for target modifiers (or default `l.tech_value == r.tech_value`)
+    // When other is None, consistency with default value is checked
+    pub fn consistent(&self, opts: &Options, other: Option<&TargetModifier>) -> bool {
+        assert!(other.is_none() || self.opt == other.unwrap().opt);
+        match self.opt {
+            OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
+                UnstableOptionsTargetModifiers::sanitizer => {
+                    return target_modifier_consistency_check::sanitizer(self, other);
+                }
+                UnstableOptionsTargetModifiers::sanitizer_cfi_normalize_integers => {
+                    return target_modifier_consistency_check::sanitizer_cfi_normalize_integers(
+                        opts, self, other,
+                    );
+                }
+                _ => {}
+            },
+            _ => {}
+        };
+        match other {
+            Some(other) => self.extend().tech_value == other.extend().tech_value,
+            None => false,
+        }
+    }
 }
 
 fn tmod_push_impl(
@@ -2504,13 +2571,13 @@ written to standard error output)"),
     retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
         "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
         target features (default: no)"),
-    sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
+    sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
         "use a sanitizer"),
     sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
         "enable canonical jump tables (default: yes)"),
     sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable generalizing pointer types (default: no)"),
-    sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
+    sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED TARGET_MODIFIER],
         "enable normalizing integer types (default: no)"),
     sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
         "additional ABI list files that control how shadow parameters are passed (comma separated)"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 96767d05439..3525c7c1d1a 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1,10 +1,9 @@
 use std::any::Any;
-use std::ops::{Div, Mul};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
-use std::{env, fmt, io};
+use std::{env, io};
 
 use rand::{RngCore, rng};
 use rustc_ast::NodeId;
@@ -25,6 +24,7 @@ use rustc_errors::{
     Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort,
     LintEmitter, TerminalUrl, fallback_fluent_bundle,
 };
+use rustc_hir::limit::Limit;
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
 use rustc_span::edition::Edition;
@@ -62,64 +62,6 @@ pub enum CtfeBacktrace {
     Immediate,
 }
 
-/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against
-/// limits are consistent throughout the compiler.
-#[derive(Clone, Copy, Debug, HashStable_Generic)]
-pub struct Limit(pub usize);
-
-impl Limit {
-    /// Create a new limit from a `usize`.
-    pub fn new(value: usize) -> Self {
-        Limit(value)
-    }
-
-    /// Create a new unlimited limit.
-    pub fn unlimited() -> Self {
-        Limit(usize::MAX)
-    }
-
-    /// Check that `value` is within the limit. Ensures that the same comparisons are used
-    /// throughout the compiler, as mismatches can cause ICEs, see #72540.
-    #[inline]
-    pub fn value_within_limit(&self, value: usize) -> bool {
-        value <= self.0
-    }
-}
-
-impl From<usize> for Limit {
-    fn from(value: usize) -> Self {
-        Self::new(value)
-    }
-}
-
-impl fmt::Display for Limit {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
-impl Div<usize> for Limit {
-    type Output = Limit;
-
-    fn div(self, rhs: usize) -> Self::Output {
-        Limit::new(self.0 / rhs)
-    }
-}
-
-impl Mul<usize> for Limit {
-    type Output = Limit;
-
-    fn mul(self, rhs: usize) -> Self::Output {
-        Limit::new(self.0 * rhs)
-    }
-}
-
-impl rustc_errors::IntoDiagArg for Limit {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
-        self.to_string().into_diag_arg(&mut None)
-    }
-}
-
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
 pub struct Limits {
     /// The maximum recursion limit for potentially infinitely recursive
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 77260d07c99..e5108d8b7e9 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2162,6 +2162,7 @@ symbols! {
         target_family,
         target_feature,
         target_feature_11,
+        target_feature_inline_always,
         target_has_atomic,
         target_has_atomic_equal_alignment,
         target_has_atomic_load_store,
@@ -2280,6 +2281,8 @@ symbols! {
         unboxed_closures,
         unchecked_add,
         unchecked_div,
+        unchecked_funnel_shl,
+        unchecked_funnel_shr,
         unchecked_mul,
         unchecked_rem,
         unchecked_shl,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 0cbd48ba08c..0655c2d5e81 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -82,9 +82,13 @@ pub(super) fn mangle<'tcx>(
 }
 
 pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> String {
-    if item_name == "rust_eh_personality" {
+    match item_name {
         // rust_eh_personality must not be renamed as LLVM hard-codes the name
-        return "rust_eh_personality".to_owned();
+        "rust_eh_personality" => return item_name.to_owned(),
+        // Apple availability symbols need to not be mangled to be usable by
+        // C/Objective-C code.
+        "__isPlatformVersionAtLeast" | "__isOSVersionAtLeast" => return item_name.to_owned(),
+        _ => {}
     }
 
     let prefix = "_R";
diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index d567ad401bb..9213d73e24e 100644
--- a/compiler/rustc_target/src/callconv/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
@@ -8,16 +8,16 @@ use crate::spec::HasTargetSpec;
 
 #[derive(Copy, Clone)]
 enum RegPassKind {
-    Float(Reg),
-    Integer(Reg),
+    Float { offset_from_start: Size, ty: Reg },
+    Integer { offset_from_start: Size, ty: Reg },
     Unknown,
 }
 
 #[derive(Copy, Clone)]
 enum FloatConv {
-    FloatPair(Reg, Reg),
+    FloatPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
     Float(Reg),
-    MixedPair(Reg, Reg),
+    MixedPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
 }
 
 #[derive(Copy, Clone)]
@@ -37,6 +37,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
     flen: u64,
     field1_kind: &mut RegPassKind,
     field2_kind: &mut RegPassKind,
+    offset_from_start: Size,
 ) -> Result<(), CannotUseFpConv>
 where
     Ty: TyAbiInterface<'a, C> + Copy,
@@ -49,16 +50,16 @@ where
                 }
                 match (*field1_kind, *field2_kind) {
                     (RegPassKind::Unknown, _) => {
-                        *field1_kind = RegPassKind::Integer(Reg {
-                            kind: RegKind::Integer,
-                            size: arg_layout.size,
-                        });
+                        *field1_kind = RegPassKind::Integer {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
+                        };
                     }
-                    (RegPassKind::Float(_), RegPassKind::Unknown) => {
-                        *field2_kind = RegPassKind::Integer(Reg {
-                            kind: RegKind::Integer,
-                            size: arg_layout.size,
-                        });
+                    (RegPassKind::Float { .. }, RegPassKind::Unknown) => {
+                        *field2_kind = RegPassKind::Integer {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
+                        };
                     }
                     _ => return Err(CannotUseFpConv),
                 }
@@ -69,12 +70,16 @@ where
                 }
                 match (*field1_kind, *field2_kind) {
                     (RegPassKind::Unknown, _) => {
-                        *field1_kind =
-                            RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
+                        *field1_kind = RegPassKind::Float {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Float, size: arg_layout.size },
+                        };
                     }
                     (_, RegPassKind::Unknown) => {
-                        *field2_kind =
-                            RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
+                        *field2_kind = RegPassKind::Float {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Float, size: arg_layout.size },
+                        };
                     }
                     _ => return Err(CannotUseFpConv),
                 }
@@ -96,13 +101,14 @@ where
                             flen,
                             field1_kind,
                             field2_kind,
+                            offset_from_start,
                         );
                     }
                     return Err(CannotUseFpConv);
                 }
             }
             FieldsShape::Array { count, .. } => {
-                for _ in 0..count {
+                for i in 0..count {
                     let elem_layout = arg_layout.field(cx, 0);
                     should_use_fp_conv_helper(
                         cx,
@@ -111,6 +117,7 @@ where
                         flen,
                         field1_kind,
                         field2_kind,
+                        offset_from_start + elem_layout.size * i,
                     )?;
                 }
             }
@@ -121,7 +128,15 @@ where
                 }
                 for i in arg_layout.fields.index_by_increasing_offset() {
                     let field = arg_layout.field(cx, i);
-                    should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?;
+                    should_use_fp_conv_helper(
+                        cx,
+                        &field,
+                        xlen,
+                        flen,
+                        field1_kind,
+                        field2_kind,
+                        offset_from_start + arg_layout.fields.offset(i),
+                    )?;
                 }
             }
         },
@@ -140,14 +155,52 @@ where
 {
     let mut field1_kind = RegPassKind::Unknown;
     let mut field2_kind = RegPassKind::Unknown;
-    if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() {
+    if should_use_fp_conv_helper(
+        cx,
+        arg,
+        xlen,
+        flen,
+        &mut field1_kind,
+        &mut field2_kind,
+        Size::ZERO,
+    )
+    .is_err()
+    {
         return None;
     }
     match (field1_kind, field2_kind) {
-        (RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)),
-        (RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)),
-        (RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)),
-        (RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)),
+        (
+            RegPassKind::Integer { offset_from_start, .. }
+            | RegPassKind::Float { offset_from_start, .. },
+            _,
+        ) if offset_from_start != Size::ZERO => {
+            panic!("type {:?} has a first field with non-zero offset {offset_from_start:?}", arg.ty)
+        }
+        (
+            RegPassKind::Integer { ty: first_ty, .. },
+            RegPassKind::Float { offset_from_start, ty: second_ty },
+        ) => Some(FloatConv::MixedPair {
+            first_ty,
+            second_ty_offset_from_start: offset_from_start,
+            second_ty,
+        }),
+        (
+            RegPassKind::Float { ty: first_ty, .. },
+            RegPassKind::Integer { offset_from_start, ty: second_ty },
+        ) => Some(FloatConv::MixedPair {
+            first_ty,
+            second_ty_offset_from_start: offset_from_start,
+            second_ty,
+        }),
+        (
+            RegPassKind::Float { ty: first_ty, .. },
+            RegPassKind::Float { offset_from_start, ty: second_ty },
+        ) => Some(FloatConv::FloatPair {
+            first_ty,
+            second_ty_offset_from_start: offset_from_start,
+            second_ty,
+        }),
+        (RegPassKind::Float { ty, .. }, RegPassKind::Unknown) => Some(FloatConv::Float(ty)),
         _ => None,
     }
 }
@@ -165,11 +218,19 @@ where
             FloatConv::Float(f) => {
                 arg.cast_to(f);
             }
-            FloatConv::FloatPair(l, r) => {
-                arg.cast_to(CastTarget::pair(l, r));
+            FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty } => {
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
             }
-            FloatConv::MixedPair(l, r) => {
-                arg.cast_to(CastTarget::pair(l, r));
+            FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty } => {
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
             }
         }
         return false;
@@ -233,15 +294,27 @@ fn classify_arg<'a, Ty, C>(
                 arg.cast_to(f);
                 return;
             }
-            Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => {
+            Some(FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty })
+                if *avail_fprs >= 2 =>
+            {
                 *avail_fprs -= 2;
-                arg.cast_to(CastTarget::pair(l, r));
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
                 return;
             }
-            Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => {
+            Some(FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty })
+                if *avail_fprs >= 1 && *avail_gprs >= 1 =>
+            {
                 *avail_gprs -= 1;
                 *avail_fprs -= 1;
-                arg.cast_to(CastTarget::pair(l, r));
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
                 return;
             }
             _ => (),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
index f1b6fa123de..cd55576ef81 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
@@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
         llvm_target: "aarch64-pc-windows-msvc".into(),
         metadata: TargetMetadata {
             description: Some("ARM64 Windows MSVC".into()),
-            tier: Some(2),
+            tier: Some(1),
             host_tools: Some(true),
             std: Some(true),
         },
diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
index 598f0f19f0d..cada0dd640a 100644
--- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
@@ -6,7 +6,7 @@ use crate::spec::{
 pub(crate) fn target() -> Target {
     Target {
         arch: "nvptx64".into(),
-        data_layout: "e-p6:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64".into(),
+        data_layout: "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64".into(),
         llvm_target: "nvptx64-nvidia-cuda".into(),
         metadata: TargetMetadata {
             description: Some("--emit=asm generates PTX code that runs on NVIDIA GPUs".into()),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 9447612d026..d3a17232a40 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -91,7 +91,6 @@ mod suggest;
 pub mod need_type_info;
 pub mod nice_region_error;
 pub mod region;
-pub mod sub_relations;
 
 /// Makes a valid string literal from a string by escaping special characters (" and \),
 /// unless they are already escaped.
@@ -318,7 +317,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     let (expected, found) = if expected_str == found_str {
                         (join_path_syms(&expected_abs), join_path_syms(&found_abs))
                     } else {
-                        (expected_str.clone(), found_str.clone())
+                        (expected_str, found_str)
                     };
 
                     // We've displayed "expected `a::b`, found `a::b`". We add context to
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index ec2287ed516..edab530590b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -894,7 +894,8 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                 use ty::{Infer, TyVar};
                 match (inner_ty.kind(), target_ty.kind()) {
                     (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
-                        self.tecx.sub_relations.borrow_mut().unified(self.tecx, a_vid, b_vid)
+                        self.tecx.sub_unification_table_root_var(a_vid)
+                            == self.tecx.sub_unification_table_root_var(b_vid)
                     }
                     _ => false,
                 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs
deleted file mode 100644
index ef26a8ff7b8..00000000000
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::undo_log::NoUndo;
-use rustc_data_structures::unify as ut;
-use rustc_middle::ty;
-
-use crate::infer::InferCtxt;
-
-#[derive(Debug, Copy, Clone, PartialEq)]
-struct SubId(u32);
-impl ut::UnifyKey for SubId {
-    type Value = ();
-    #[inline]
-    fn index(&self) -> u32 {
-        self.0
-    }
-    #[inline]
-    fn from_index(i: u32) -> SubId {
-        SubId(i)
-    }
-    fn tag() -> &'static str {
-        "SubId"
-    }
-}
-
-/// When reporting ambiguity errors, we sometimes want to
-/// treat all inference vars which are subtypes of each
-/// others as if they are equal. For this case we compute
-/// the transitive closure of our subtype obligations here.
-///
-/// E.g. when encountering ambiguity errors, we want to suggest
-/// specifying some method argument or to add a type annotation
-/// to a local variable. Because subtyping cannot change the
-/// shape of a type, it's fine if the cause of the ambiguity error
-/// is only related to the suggested variable via subtyping.
-///
-/// Even for something like `let x = returns_arg(); x.method();` the
-/// type of `x` is only a supertype of the argument of `returns_arg`. We
-/// still want to suggest specifying the type of the argument.
-#[derive(Default)]
-pub struct SubRelations {
-    map: FxHashMap<ty::TyVid, SubId>,
-    table: ut::UnificationTableStorage<SubId>,
-}
-
-impl SubRelations {
-    fn get_id<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, vid: ty::TyVid) -> SubId {
-        let root_vid = infcx.root_var(vid);
-        *self.map.entry(root_vid).or_insert_with(|| self.table.with_log(&mut NoUndo).new_key(()))
-    }
-
-    pub fn add_constraints<'tcx>(
-        &mut self,
-        infcx: &InferCtxt<'tcx>,
-        obls: impl IntoIterator<Item = ty::Predicate<'tcx>>,
-    ) {
-        for p in obls {
-            let (a, b) = match p.kind().skip_binder() {
-                ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
-                    (a, b)
-                }
-                ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b),
-                _ => continue,
-            };
-
-            match (a.kind(), b.kind()) {
-                (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
-                    let a = self.get_id(infcx, a_vid);
-                    let b = self.get_id(infcx, b_vid);
-                    self.table.with_log(&mut NoUndo).unify_var_var(a, b).unwrap();
-                }
-                _ => continue,
-            }
-        }
-    }
-
-    pub fn unified<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, a: ty::TyVid, b: ty::TyVid) -> bool {
-        let a = self.get_id(infcx, a);
-        let b = self.get_id(infcx, b);
-        self.table.with_log(&mut NoUndo).unioned(a, b)
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
index 82695688ae8..cce20b05c79 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
@@ -7,8 +7,6 @@ use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty};
 
-use crate::error_reporting::infer::sub_relations;
-
 pub mod infer;
 pub mod traits;
 
@@ -21,7 +19,6 @@ pub mod traits;
 /// methods which should not be used during the happy path.
 pub struct TypeErrCtxt<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'tcx>,
-    pub sub_relations: std::cell::RefCell<sub_relations::SubRelations>,
 
     pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
     pub fallback_has_occurred: bool,
@@ -38,7 +35,6 @@ impl<'tcx> InferCtxt<'tcx> {
     fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
         TypeErrCtxt {
             infcx: self,
-            sub_relations: Default::default(),
             typeck_results: None,
             fallback_has_occurred: false,
             normalize_fn_sig: Box::new(|fn_sig| fn_sig),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index c8500b2d9d4..f794ff632c5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -139,10 +139,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         mut errors: Vec<FulfillmentError<'tcx>>,
     ) -> ErrorGuaranteed {
-        self.sub_relations
-            .borrow_mut()
-            .add_constraints(self, errors.iter().map(|e| e.obligation.predicate));
-
         #[derive(Debug)]
         struct ErrorDescriptor<'tcx> {
             goal: Goal<'tcx, ty::Predicate<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
index 4f1f5c330e5..a0876d8fe75 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
@@ -3,10 +3,10 @@ use std::fmt;
 use rustc_errors::{Diag, E0275, EmissionGuarantee, ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::limit::Limit;
 use rustc_infer::traits::{Obligation, PredicateObligation};
 use rustc_middle::ty::print::{FmtPrinter, Print};
 use rustc_middle::ty::{self, TyCtxt, Upcast};
-use rustc_session::Limit;
 use rustc_span::Span;
 use tracing::debug;
 
@@ -67,7 +67,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // We don't need to save the type to a file, we will be talking about this type already
                 // in a separate note when we explain the obligation, so it will be available that way.
                 let mut p: FmtPrinter<'_, '_> =
-                    FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
+                    FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(6));
                 value.print(&mut p).unwrap();
                 p.into_buffer()
             } else {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 40a27c9aebe..f6dbbeb51ca 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -32,8 +32,8 @@ use rustc_middle::ty::print::{
 };
 use rustc_middle::ty::{
     self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
-    TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, suggest_arbitrary_trait_bound,
-    suggest_constraining_type_param,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, TypeckResults, Upcast,
+    suggest_arbitrary_trait_bound, suggest_constraining_type_param,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::LocalDefId;
@@ -263,6 +263,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             _ => (false, None),
         };
 
+        let mut finder = ParamFinder { .. };
+        finder.visit_binder(&trait_pred);
+
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
         //        don't suggest `T: Sized + ?Sized`.
         loop {
@@ -411,6 +414,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     }
                 }
 
+                hir::Node::TraitItem(hir::TraitItem {
+                    generics,
+                    kind: hir::TraitItemKind::Fn(..),
+                    ..
+                })
+                | hir::Node::ImplItem(hir::ImplItem {
+                    generics,
+                    trait_item_def_id: None,
+                    kind: hir::ImplItemKind::Fn(..),
+                    ..
+                }) if finder.can_suggest_bound(generics) => {
+                    // Missing generic type parameter bound.
+                    suggest_arbitrary_trait_bound(
+                        self.tcx,
+                        generics,
+                        err,
+                        trait_pred,
+                        associated_ty,
+                    );
+                }
                 hir::Node::Item(hir::Item {
                     kind:
                         hir::ItemKind::Struct(_, generics, _)
@@ -423,7 +446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         | hir::ItemKind::Const(_, generics, _, _)
                         | hir::ItemKind::TraitAlias(_, generics, _),
                     ..
-                }) if !param_ty => {
+                }) if finder.can_suggest_bound(generics) => {
                     // Missing generic type parameter bound.
                     if suggest_arbitrary_trait_bound(
                         self.tcx,
@@ -5068,8 +5091,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
         // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
         // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
-        let mut visitor =
-            FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
+        let mut visitor = FindTypeParam { param: param.name.ident().name, .. };
         visitor.visit_item(item);
         if visitor.invalid_spans.is_empty() {
             return false;
@@ -5228,7 +5250,7 @@ fn hint_missing_borrow<'tcx>(
 /// Used to suggest replacing associated types with an explicit type in `where` clauses.
 #[derive(Debug)]
 pub struct SelfVisitor<'v> {
-    pub paths: Vec<&'v hir::Ty<'v>>,
+    pub paths: Vec<&'v hir::Ty<'v>> = Vec::new(),
     pub name: Option<Symbol>,
 }
 
@@ -5599,7 +5621,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
                 );
                 // Search for the associated type `Self::{name}`, get
                 // its type and suggest replacing the bound with it.
-                let mut visitor = SelfVisitor { paths: vec![], name: Some(name) };
+                let mut visitor = SelfVisitor { name: Some(name), .. };
                 visitor.visit_trait_ref(trait_ref);
                 for path in visitor.paths {
                     err.span_suggestion_verbose(
@@ -5610,7 +5632,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
                     );
                 }
             } else {
-                let mut visitor = SelfVisitor { paths: vec![], name: None };
+                let mut visitor = SelfVisitor { name: None, .. };
                 visitor.visit_trait_ref(trait_ref);
                 let span: MultiSpan =
                     visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into();
@@ -5640,8 +5662,8 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
 /// `param: ?Sized` would be a valid constraint.
 struct FindTypeParam {
     param: rustc_span::Symbol,
-    invalid_spans: Vec<Span>,
-    nested: bool,
+    invalid_spans: Vec<Span> = Vec::new(),
+    nested: bool = false,
 }
 
 impl<'v> Visitor<'v> for FindTypeParam {
@@ -5679,3 +5701,38 @@ impl<'v> Visitor<'v> for FindTypeParam {
         }
     }
 }
+
+/// Look for type parameters in predicates. We use this to identify whether a bound is suitable in
+/// on a given item.
+struct ParamFinder {
+    params: Vec<Symbol> = Vec::new(),
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamFinder {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+        match t.kind() {
+            ty::Param(p) => self.params.push(p.name),
+            _ => {}
+        }
+        t.super_visit_with(self)
+    }
+}
+
+impl ParamFinder {
+    /// Whether the `hir::Generics` of the current item can suggest the evaluated bound because its
+    /// references to type parameters are present in the generics.
+    fn can_suggest_bound(&self, generics: &hir::Generics<'_>) -> bool {
+        if self.params.is_empty() {
+            // There are no references to type parameters at all, so suggesting the bound
+            // would be reasonable.
+            return true;
+        }
+        generics.params.iter().any(|p| match p.name {
+            hir::ParamName::Plain(p_name) => {
+                // All of the parameters in the bound can be referenced in the current item.
+                self.params.iter().any(|p| *p == p_name.name || *p == kw::SelfUpper)
+            }
+            _ => true,
+        })
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 7c6b7b14ecb..4c50c44b841 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -184,10 +184,9 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         R: Debug + TypeFoldable<TyCtxt<'tcx>>,
         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
     {
-        let (infcx, key, canonical_inference_vars) =
-            self.build_with_canonical(DUMMY_SP, canonical_key);
+        let (infcx, key, var_values) = self.build_with_canonical(DUMMY_SP, canonical_key);
         let ocx = ObligationCtxt::new(&infcx);
         let value = operation(&ocx, key)?;
-        ocx.make_canonicalized_query_response(canonical_inference_vars, value)
+        ocx.make_canonicalized_query_response(var_values, value)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index e2b22f7bab7..fc0cf8f140a 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -19,6 +19,7 @@
 #![feature(assert_matches)]
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
+#![feature(default_field_values)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(iterator_try_reduce)]
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index e6a2761db5a..16f444486a6 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -126,13 +126,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
             }
             ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. })
             | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
-                if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() {
-                    // FIXME: We also need to register a subtype relation between these vars
-                    // when those are added, and if they aren't in the same sub root then
-                    // we should mark this goal as `has_changed`.
-                    Some(Certainty::AMBIGUOUS)
-                } else {
-                    None
+                match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) {
+                    (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
+                        self.sub_unify_ty_vids_raw(a_vid, b_vid);
+                        Some(Certainty::AMBIGUOUS)
+                    }
+                    _ => None,
                 }
             }
             ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => {
@@ -238,13 +237,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         canonical.instantiate(self.tcx, &values)
     }
 
-    fn instantiate_canonical_var_with_infer(
+    fn instantiate_canonical_var(
         &self,
         kind: CanonicalVarKind<'tcx>,
         span: Span,
+        var_values: &[ty::GenericArg<'tcx>],
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> ty::GenericArg<'tcx> {
-        self.0.instantiate_canonical_var(span, kind, universe_map)
+        self.0.instantiate_canonical_var(span, kind, var_values, universe_map)
     }
 
     fn add_item_bounds_for_hidden_type(
diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs
index 819b8e3231c..8f72bdf0972 100644
--- a/compiler/rustc_traits/src/evaluate_obligation.rs
+++ b/compiler/rustc_traits/src/evaluate_obligation.rs
@@ -19,7 +19,7 @@ fn evaluate_obligation<'tcx>(
 ) -> Result<EvaluationResult, OverflowError> {
     assert!(!tcx.next_trait_solver_globally());
     debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
-    let (ref infcx, goal, _canonical_inference_vars) =
+    let (ref infcx, goal, _var_values) =
         tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
     debug!("evaluate_obligation: goal={:#?}", goal);
     let ParamEnvAnd { param_env, value: predicate } = goal;
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 13d56889bd1..0ef435b1a0e 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -2,11 +2,11 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
+use rustc_hir::limit::Limit;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{AlwaysRequiresDrop, needs_drop_components};
 use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt};
-use rustc_session::Limit;
 use rustc_span::sym;
 use tracing::{debug, instrument};
 
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index d55e9b3b1be..6ccddb17ff2 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
+arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
 derive-where = "1.2.7"
 ena = "0.14.3"
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index de2a9186e7c..ecf3ae4f8b2 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -1,7 +1,7 @@
 use std::fmt;
-use std::hash::Hash;
 use std::ops::Index;
 
+use arrayvec::ArrayVec;
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
@@ -91,8 +91,18 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
 )]
 pub enum CanonicalVarKind<I: Interner> {
-    /// Some kind of type inference variable.
-    Ty(CanonicalTyVarKind),
+    /// General type variable `?T` that can be unified with arbitrary types.
+    ///
+    /// We also store the index of the first type variable which is sub-unified
+    /// with this one. If there is no inference variable related to this one,
+    /// its `sub_root` just points to itself.
+    Ty { ui: UniverseIndex, sub_root: ty::BoundVar },
+
+    /// Integral type variable `?I` (that can only be unified with integral types).
+    Int,
+
+    /// Floating-point type variable `?F` (that can only be unified with float types).
+    Float,
 
     /// A "placeholder" that represents "any type".
     PlaceholderTy(I::PlaceholderTy),
@@ -117,15 +127,13 @@ impl<I: Interner> Eq for CanonicalVarKind<I> {}
 impl<I: Interner> CanonicalVarKind<I> {
     pub fn universe(self) -> UniverseIndex {
         match self {
-            CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
+            CanonicalVarKind::Ty { ui, sub_root: _ } => ui,
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::Const(ui) => ui,
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(),
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(),
             CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(),
-            CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
-                UniverseIndex::ROOT
-            }
+            CanonicalVarKind::Float | CanonicalVarKind::Int => UniverseIndex::ROOT,
         }
     }
 
@@ -135,9 +143,7 @@ impl<I: Interner> CanonicalVarKind<I> {
     /// the updated universe is not the root.
     pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> {
         match self {
-            CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
-                CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
-            }
+            CanonicalVarKind::Ty { ui: _, sub_root } => CanonicalVarKind::Ty { ui, sub_root },
             CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui),
             CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui),
 
@@ -150,7 +156,7 @@ impl<I: Interner> CanonicalVarKind<I> {
             CanonicalVarKind::PlaceholderConst(placeholder) => {
                 CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
             }
-            CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+            CanonicalVarKind::Int | CanonicalVarKind::Float => {
                 assert_eq!(ui, UniverseIndex::ROOT);
                 self
             }
@@ -159,19 +165,23 @@ impl<I: Interner> CanonicalVarKind<I> {
 
     pub fn is_existential(self) -> bool {
         match self {
-            CanonicalVarKind::Ty(_) => true,
-            CanonicalVarKind::PlaceholderTy(_) => false,
-            CanonicalVarKind::Region(_) => true,
-            CanonicalVarKind::PlaceholderRegion(..) => false,
-            CanonicalVarKind::Const(_) => true,
-            CanonicalVarKind::PlaceholderConst(_) => false,
+            CanonicalVarKind::Ty { .. }
+            | CanonicalVarKind::Int
+            | CanonicalVarKind::Float
+            | CanonicalVarKind::Region(_)
+            | CanonicalVarKind::Const(_) => true,
+            CanonicalVarKind::PlaceholderTy(_)
+            | CanonicalVarKind::PlaceholderRegion(..)
+            | CanonicalVarKind::PlaceholderConst(_) => false,
         }
     }
 
     pub fn is_region(self) -> bool {
         match self {
             CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
-            CanonicalVarKind::Ty(_)
+            CanonicalVarKind::Ty { .. }
+            | CanonicalVarKind::Int
+            | CanonicalVarKind::Float
             | CanonicalVarKind::PlaceholderTy(_)
             | CanonicalVarKind::Const(_)
             | CanonicalVarKind::PlaceholderConst(_) => false,
@@ -180,7 +190,11 @@ impl<I: Interner> CanonicalVarKind<I> {
 
     pub fn expect_placeholder_index(self) -> usize {
         match self {
-            CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
+            CanonicalVarKind::Ty { .. }
+            | CanonicalVarKind::Int
+            | CanonicalVarKind::Float
+            | CanonicalVarKind::Region(_)
+            | CanonicalVarKind::Const(_) => {
                 panic!("expected placeholder: {self:?}")
             }
 
@@ -191,27 +205,6 @@ impl<I: Interner> CanonicalVarKind<I> {
     }
 }
 
-/// Rust actually has more than one category of type variables;
-/// notably, the type variables we create for literals (e.g., 22 or
-/// 22.) can only be instantiated with integral/float types (e.g.,
-/// usize or f32). In order to faithfully reproduce a type, we need to
-/// know what set of types a given type variable can be unified with.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-#[cfg_attr(
-    feature = "nightly",
-    derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
-)]
-pub enum CanonicalTyVarKind {
-    /// General type variable `?T` that can be unified with arbitrary types.
-    General(UniverseIndex),
-
-    /// Integral type variable `?I` (that can only be unified with integral types).
-    Int,
-
-    /// Floating-point type variable `?F` (that can only be unified with float types).
-    Float,
-}
-
 /// A set of values corresponding to the canonical variables from some
 /// `Canonical`. You can give these values to
 /// `canonical_value.instantiate` to instantiate them into the canonical
@@ -287,7 +280,10 @@ impl<I: Interner> CanonicalVarValues<I> {
             var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
                 |(i, kind)| -> I::GenericArg {
                     match kind {
-                        CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
+                        CanonicalVarKind::Ty { .. }
+                        | CanonicalVarKind::Int
+                        | CanonicalVarKind::Float
+                        | CanonicalVarKind::PlaceholderTy(_) => {
                             Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
                                 .into()
                         }
@@ -311,6 +307,37 @@ impl<I: Interner> CanonicalVarValues<I> {
         CanonicalVarValues { var_values: Default::default() }
     }
 
+    pub fn instantiate(
+        cx: I,
+        variables: I::CanonicalVarKinds,
+        mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg,
+    ) -> CanonicalVarValues<I> {
+        // Instantiating `CanonicalVarValues` is really hot, but limited to less than
+        // 4 most of the time. Avoid creating a `Vec` here.
+        if variables.len() <= 4 {
+            let mut var_values = ArrayVec::<_, 4>::new();
+            for info in variables.iter() {
+                var_values.push(f(&var_values, info));
+            }
+            CanonicalVarValues { var_values: cx.mk_args(&var_values) }
+        } else {
+            CanonicalVarValues::instantiate_cold(cx, variables, f)
+        }
+    }
+
+    #[cold]
+    fn instantiate_cold(
+        cx: I,
+        variables: I::CanonicalVarKinds,
+        mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg,
+    ) -> CanonicalVarValues<I> {
+        let mut var_values = Vec::with_capacity(variables.len());
+        for info in variables.iter() {
+            var_values.push(f(&var_values, info));
+        }
+        CanonicalVarValues { var_values: cx.mk_args(&var_values) }
+    }
+
     #[inline]
     pub fn len(&self) -> usize {
         self.var_values.len()
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs
index 5a05630e1bd..ed6416a7f55 100644
--- a/compiler/rustc_type_ir/src/fast_reject.rs
+++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -122,7 +122,7 @@ pub fn simplify_type<I: Interner>(
         ty::Int(int_type) => Some(SimplifiedType::Int(int_type)),
         ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)),
         ty::Float(float_type) => Some(SimplifiedType::Float(float_type)),
-        ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id())),
+        ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id().into())),
         ty::Str => Some(SimplifiedType::Str),
         ty::Array(..) => Some(SimplifiedType::Array),
         ty::Slice(..) => Some(SimplifiedType::Slice),
@@ -135,11 +135,11 @@ pub fn simplify_type<I: Interner>(
             _ => Some(SimplifiedType::MarkerTraitObject),
         },
         ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
-        ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => {
-            Some(SimplifiedType::Closure(def_id))
-        }
-        ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)),
-        ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)),
+        ty::FnDef(def_id, _) => Some(SimplifiedType::Closure(def_id.into())),
+        ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id.into())),
+        ty::CoroutineClosure(def_id, _) => Some(SimplifiedType::Closure(def_id.into())),
+        ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id.into())),
+        ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id.into())),
         ty::Never => Some(SimplifiedType::Never),
         ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
         ty::FnPtr(sig_tys, _hdr) => {
@@ -161,7 +161,7 @@ pub fn simplify_type<I: Interner>(
             }
             TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None,
         },
-        ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
+        ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id.into())),
         ty::Error(_) => Some(SimplifiedType::Error),
         ty::Bound(..) | ty::Infer(_) => None,
     }
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index b4462294700..56962b4597b 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -158,6 +158,7 @@ pub trait InferCtxtLike: Sized {
     fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
 
     fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
+    fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid;
     fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
 
     fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
@@ -197,6 +198,7 @@ pub trait InferCtxtLike: Sized {
     ) -> U;
 
     fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid);
+    fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid);
     fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
     fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
     fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 64063b1a365..ecfc05a6e20 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -74,7 +74,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self;
 
-    fn new_foreign(interner: I, def_id: I::DefId) -> Self;
+    fn new_foreign(interner: I, def_id: I::ForeignId) -> Self;
 
     fn new_dynamic(
         interner: I,
@@ -83,17 +83,21 @@ pub trait Ty<I: Interner<Ty = Self>>:
         kind: ty::DynKind,
     ) -> Self;
 
-    fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
+    fn new_coroutine(interner: I, def_id: I::CoroutineId, args: I::GenericArgs) -> Self;
 
-    fn new_coroutine_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
+    fn new_coroutine_closure(
+        interner: I,
+        def_id: I::CoroutineClosureId,
+        args: I::GenericArgs,
+    ) -> Self;
 
-    fn new_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
+    fn new_closure(interner: I, def_id: I::ClosureId, args: I::GenericArgs) -> Self;
 
-    fn new_coroutine_witness(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
+    fn new_coroutine_witness(interner: I, def_id: I::CoroutineId, args: I::GenericArgs) -> Self;
 
     fn new_coroutine_witness_for_coroutine(
         interner: I,
-        def_id: I::DefId,
+        def_id: I::CoroutineId,
         coroutine_args: I::GenericArgs,
     ) -> Self;
 
@@ -112,7 +116,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
         It: Iterator<Item = T>,
         T: CollectAndApply<Self, Self>;
 
-    fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
+    fn new_fn_def(interner: I, def_id: I::FunctionId, args: I::GenericArgs) -> Self;
 
     fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self;
 
@@ -599,7 +603,7 @@ pub trait ParamLike: Copy + Debug + Hash + Eq {
 }
 
 pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
-    fn def_id(self) -> I::DefId;
+    fn def_id(self) -> I::AdtId;
 
     fn is_struct(self) -> bool;
 
@@ -646,6 +650,16 @@ pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
     fn as_local(self) -> Option<I::LocalDefId>;
 }
 
+pub trait SpecificDefId<I: Interner>:
+    DefId<I> + Into<I::DefId> + TryFrom<I::DefId, Error: std::fmt::Debug>
+{
+}
+
+impl<I: Interner, T: DefId<I> + Into<I::DefId> + TryFrom<I::DefId, Error: std::fmt::Debug>>
+    SpecificDefId<I> for T
+{
+}
+
 pub trait BoundExistentialPredicates<I: Interner>:
     Copy + Debug + Hash + Eq + Relate<I> + SliceLike<Item = ty::Binder<I, ty::ExistentialPredicate<I>>>
 {
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index f5448baf8c0..3a83b1739ff 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -1,3 +1,4 @@
+use std::borrow::Borrow;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Deref;
@@ -8,7 +9,7 @@ use rustc_index::bit_set::DenseBitSet;
 use crate::fold::TypeFoldable;
 use crate::inherent::*;
 use crate::ir_print::IrPrint;
-use crate::lang_items::{SolverLangItem, SolverTraitLangItem};
+use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
 use crate::relate::Relate;
 use crate::solve::{
     CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, inspect,
@@ -40,13 +41,20 @@ pub trait Interner:
 
     type DefId: DefId<Self>;
     type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
-    /// A `DefId` of a trait.
-    ///
-    /// In rustc this is just a `DefId`, but rust-analyzer uses different types for different items.
-    ///
-    /// Note: The `TryFrom<DefId>` always succeeds (in rustc), so don't use it to check if some `DefId`
-    /// is a trait!
-    type TraitId: DefId<Self> + Into<Self::DefId> + TryFrom<Self::DefId, Error: std::fmt::Debug>;
+    // Various more specific `DefId`s.
+    //
+    // rustc just defines them all to be `DefId`, but rust-analyzer uses different types so this is convenient for it.
+    //
+    // Note: The `TryFrom<DefId>` always succeeds (in rustc), so don't use it to check if some `DefId`
+    // is of some specific type!
+    type TraitId: SpecificDefId<Self>;
+    type ForeignId: SpecificDefId<Self>;
+    type FunctionId: SpecificDefId<Self>;
+    type ClosureId: SpecificDefId<Self>;
+    type CoroutineClosureId: SpecificDefId<Self>;
+    type CoroutineId: SpecificDefId<Self>;
+    type AdtId: SpecificDefId<Self>;
+    type ImplId: SpecificDefId<Self>;
     type Span: Span<Self>;
 
     type GenericArgs: GenericArgs<Self>;
@@ -198,7 +206,7 @@ pub trait Interner:
     -> ty::EarlyBinder<Self, Self::Ty>;
 
     type AdtDef: AdtDef<Self>;
-    fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef;
+    fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef;
 
     fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind;
 
@@ -239,17 +247,17 @@ pub trait Interner:
 
     fn coroutine_hidden_types(
         self,
-        def_id: Self::DefId,
+        def_id: Self::CoroutineId,
     ) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::CoroutineWitnessTypes<Self>>>;
 
     fn fn_sig(
         self,
-        def_id: Self::DefId,
+        def_id: Self::FunctionId,
     ) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::FnSig<Self>>>;
 
-    fn coroutine_movability(self, def_id: Self::DefId) -> Movability;
+    fn coroutine_movability(self, def_id: Self::CoroutineId) -> Movability;
 
-    fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId;
+    fn coroutine_for_closure(self, def_id: Self::CoroutineClosureId) -> Self::CoroutineId;
 
     fn generics_require_sized_self(self, def_id: Self::DefId) -> bool;
 
@@ -292,11 +300,11 @@ pub trait Interner:
     /// and filtering them to the outlives predicates. This is purely for performance.
     fn impl_super_outlives(
         self,
-        impl_def_id: Self::DefId,
+        impl_def_id: Self::ImplId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
 
-    fn impl_is_const(self, def_id: Self::DefId) -> bool;
-    fn fn_is_const(self, def_id: Self::DefId) -> bool;
+    fn impl_is_const(self, def_id: Self::ImplId) -> bool;
+    fn fn_is_const(self, def_id: Self::FunctionId) -> bool;
     fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool;
     fn const_conditions(
         self,
@@ -307,42 +315,49 @@ pub trait Interner:
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
 
-    fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool;
+    fn impl_self_is_guaranteed_unsized(self, def_id: Self::ImplId) -> bool;
 
-    fn has_target_features(self, def_id: Self::DefId) -> bool;
+    fn has_target_features(self, def_id: Self::FunctionId) -> bool;
 
     fn require_lang_item(self, lang_item: SolverLangItem) -> Self::DefId;
 
     fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> Self::TraitId;
 
+    fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> Self::AdtId;
+
     fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool;
 
     fn is_trait_lang_item(self, def_id: Self::TraitId, lang_item: SolverTraitLangItem) -> bool;
 
+    fn is_adt_lang_item(self, def_id: Self::AdtId, lang_item: SolverAdtLangItem) -> bool;
+
     fn is_default_trait(self, def_id: Self::TraitId) -> bool;
 
     fn as_lang_item(self, def_id: Self::DefId) -> Option<SolverLangItem>;
 
     fn as_trait_lang_item(self, def_id: Self::TraitId) -> Option<SolverTraitLangItem>;
 
+    fn as_adt_lang_item(self, def_id: Self::AdtId) -> Option<SolverAdtLangItem>;
+
     fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
 
     fn for_each_relevant_impl(
         self,
         trait_def_id: Self::TraitId,
         self_ty: Self::Ty,
-        f: impl FnMut(Self::DefId),
+        f: impl FnMut(Self::ImplId),
     );
 
     fn has_item_definition(self, def_id: Self::DefId) -> bool;
 
-    fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool;
+    fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool;
 
-    fn impl_is_default(self, impl_def_id: Self::DefId) -> bool;
+    fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool;
 
-    fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>;
+    fn impl_trait_ref(self, impl_def_id: Self::ImplId)
+    -> ty::EarlyBinder<Self, ty::TraitRef<Self>>;
 
-    fn impl_polarity(self, impl_def_id: Self::DefId) -> ty::ImplPolarity;
+    fn impl_polarity(self, impl_def_id: Self::ImplId) -> ty::ImplPolarity;
 
     fn trait_is_auto(self, trait_def_id: Self::TraitId) -> bool;
 
@@ -363,13 +378,13 @@ pub trait Interner:
 
     fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;
 
-    fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool;
-    fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool;
-    fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
-    fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
+    fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool;
+    fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool;
+    fn coroutine_is_gen(self, coroutine_def_id: Self::CoroutineId) -> bool;
+    fn coroutine_is_async_gen(self, coroutine_def_id: Self::CoroutineId) -> bool;
 
     type UnsizingParams: Deref<Target = DenseBitSet<u32>>;
-    fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
+    fn unsizing_params_for_adt(self, adt_def_id: Self::AdtId) -> Self::UnsizingParams;
 
     fn anonymize_bound_vars<T: TypeFoldable<Self>>(
         self,
@@ -383,12 +398,12 @@ pub trait Interner:
         defining_anchor: Self::LocalDefId,
     ) -> Self::LocalDefIds;
 
-    type ProbeRef: Copy + Debug + Hash + Eq + Deref<Target = inspect::Probe<Self>>;
-    fn mk_probe_ref(self, probe: inspect::Probe<Self>) -> Self::ProbeRef;
+    type Probe: Debug + Hash + Eq + Borrow<inspect::Probe<Self>>;
+    fn mk_probe(self, probe: inspect::Probe<Self>) -> Self::Probe;
     fn evaluate_root_goal_for_proof_tree_raw(
         self,
         canonical_goal: CanonicalInput<Self>,
-    ) -> (QueryResult<Self>, Self::ProbeRef);
+    ) -> (QueryResult<Self>, Self::Probe);
 }
 
 /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index 31f8f5be588..5f503d8b912 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -11,6 +11,11 @@ pub enum SolverLangItem {
     DynMetadata,
     FutureOutput,
     Metadata,
+    // tidy-alphabetical-end
+}
+
+pub enum SolverAdtLangItem {
+    // tidy-alphabetical-start
     Option,
     Poll,
     // tidy-alphabetical-end
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index 223230fde9e..690a5f65e08 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -405,7 +405,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
             Ok(if a_args.is_empty() {
                 a
             } else {
-                let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?;
+                let args = relation.relate_item_args(a_def.def_id().into(), a_args, b_args)?;
                 if args == a_args { a } else { Ty::new_adt(cx, a_def, args) }
             })
         }
@@ -524,7 +524,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
             Ok(if a_args.is_empty() {
                 a
             } else {
-                let args = relation.relate_item_args(a_def_id, a_args, b_args)?;
+                let args = relation.relate_item_args(a_def_id.into(), a_args, b_args)?;
                 if args == a_args { a } else { Ty::new_fn_def(cx, a_def_id, args) }
             })
         }
diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
index 5452ac44158..3af2f8dbaf2 100644
--- a/compiler/rustc_type_ir/src/solve/inspect.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -49,7 +49,7 @@ pub type CanonicalState<I, T> = Canonical<I, State<I, T>>;
 pub struct GoalEvaluation<I: Interner> {
     pub uncanonicalized_goal: Goal<I, I::Predicate>,
     pub orig_values: Vec<I::GenericArg>,
-    pub final_revision: I::ProbeRef,
+    pub final_revision: I::Probe,
     pub result: QueryResult<I>,
 }
 
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index b6d362d77c4..b48a8f46ebe 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -136,7 +136,7 @@ pub enum CandidateSource<I: Interner> {
     ///     let y = x.clone();
     /// }
     /// ```
-    Impl(I::DefId),
+    Impl(I::ImplId),
     /// A builtin impl generated by the compiler. When adding a new special
     /// trait, try to use actual impls whenever possible. Builtin impls should
     /// only be used in cases where the impl cannot be manually be written.
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index bde506ffd93..225d85f79c3 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -101,7 +101,7 @@ pub enum TyKind<I: Interner> {
     Adt(I::AdtDef, I::GenericArgs),
 
     /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
-    Foreign(I::DefId),
+    Foreign(I::ForeignId),
 
     /// The pointee of a string slice. Written as `str`.
     Str,
@@ -137,7 +137,7 @@ pub enum TyKind<I: Interner> {
     /// fn foo() -> i32 { 1 }
     /// let bar = foo; // bar: fn() -> i32 {foo}
     /// ```
-    FnDef(I::DefId, I::GenericArgs),
+    FnDef(I::FunctionId, I::GenericArgs),
 
     /// A pointer to a function. Written as `fn() -> i32`.
     ///
@@ -172,21 +172,21 @@ pub enum TyKind<I: Interner> {
     /// Closure args contain both the - potentially instantiated - generic parameters
     /// of its parent and some synthetic parameters. See the documentation for
     /// `ClosureArgs` for more details.
-    Closure(I::DefId, I::GenericArgs),
+    Closure(I::ClosureId, I::GenericArgs),
 
     /// The anonymous type of a closure. Used to represent the type of `async |a| a`.
     ///
     /// Coroutine-closure args contain both the - potentially instantiated - generic
     /// parameters of its parent and some synthetic parameters. See the documentation
     /// for `CoroutineClosureArgs` for more details.
-    CoroutineClosure(I::DefId, I::GenericArgs),
+    CoroutineClosure(I::CoroutineClosureId, I::GenericArgs),
 
     /// The anonymous type of a coroutine. Used to represent the type of
     /// `|a| yield a`.
     ///
     /// For more info about coroutine args, visit the documentation for
     /// `CoroutineArgs`.
-    Coroutine(I::DefId, I::GenericArgs),
+    Coroutine(I::CoroutineId, I::GenericArgs),
 
     /// A type representing the types stored inside a coroutine.
     /// This should only appear as part of the `CoroutineArgs`.
@@ -211,7 +211,7 @@ pub enum TyKind<I: Interner> {
     /// }
     /// # ;
     /// ```
-    CoroutineWitness(I::DefId, I::GenericArgs),
+    CoroutineWitness(I::CoroutineId, I::GenericArgs),
 
     /// The never type `!`.
     Never,
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index a2e16d917a9..3a6d1acfa8d 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -391,7 +391,7 @@ impl<I: Interner> CoroutineClosureSignature<I> {
         cx: I,
         parent_args: I::GenericArgsSlice,
         coroutine_kind_ty: I::Ty,
-        coroutine_def_id: I::DefId,
+        coroutine_def_id: I::CoroutineId,
         tupled_upvars_ty: I::Ty,
     ) -> I::Ty {
         let coroutine_args = ty::CoroutineArgs::new(
@@ -418,7 +418,7 @@ impl<I: Interner> CoroutineClosureSignature<I> {
         self,
         cx: I,
         parent_args: I::GenericArgsSlice,
-        coroutine_def_id: I::DefId,
+        coroutine_def_id: I::CoroutineId,
         goal_kind: ty::ClosureKind,
         env_region: I::Region,
         closure_tupled_upvars_ty: I::Ty,
diff --git a/library/Cargo.lock b/library/Cargo.lock
index c16bb3eafbd..e601137e005 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -328,7 +328,7 @@ dependencies = [
  "std_detect",
  "unwind",
  "wasi 0.11.1+wasi-snapshot-preview1",
- "wasi 0.14.3+wasi-0.2.4",
+ "wasi 0.14.4+wasi-0.2.4",
  "windows-targets 0.0.0",
 ]
 
@@ -402,9 +402,9 @@ dependencies = [
 
 [[package]]
 name = "wasi"
-version = "0.14.3+wasi-0.2.4"
+version = "0.14.4+wasi-0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95"
+checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a"
 dependencies = [
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs
index fd05f9ca464..b0027e964e4 100644
--- a/library/alloc/src/raw_vec/mod.rs
+++ b/library/alloc/src/raw_vec/mod.rs
@@ -468,10 +468,6 @@ impl<A: Allocator> RawVecInner<A> {
             return Ok(Self::new_in(alloc, elem_layout.alignment()));
         }
 
-        if let Err(err) = alloc_guard(layout.size()) {
-            return Err(err);
-        }
-
         let result = match init {
             AllocInit::Uninitialized => alloc.allocate(layout),
             #[cfg(not(no_global_oom_handling))]
@@ -662,7 +658,7 @@ impl<A: Allocator> RawVecInner<A> {
         let new_layout = layout_array(cap, elem_layout)?;
 
         let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
-        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
+        // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
 
         unsafe { self.set_ptr_and_cap(ptr, cap) };
         Ok(())
@@ -684,7 +680,7 @@ impl<A: Allocator> RawVecInner<A> {
         let new_layout = layout_array(cap, elem_layout)?;
 
         let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
-        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
+        // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
         unsafe {
             self.set_ptr_and_cap(ptr, cap);
         }
@@ -771,8 +767,6 @@ fn finish_grow<A>(
 where
     A: Allocator,
 {
-    alloc_guard(new_layout.size())?;
-
     let memory = if let Some((ptr, old_layout)) = current_memory {
         debug_assert_eq!(old_layout.align(), new_layout.align());
         unsafe {
@@ -799,23 +793,6 @@ fn handle_error(e: TryReserveError) -> ! {
     }
 }
 
-// We need to guarantee the following:
-// * We don't ever allocate `> isize::MAX` byte-size objects.
-// * We don't overflow `usize::MAX` and actually allocate too little.
-//
-// On 64-bit we just need to check for overflow since trying to allocate
-// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add
-// an extra guard for this in case we're running on a platform which can use
-// all 4GB in user-space, e.g., PAE or x32.
-#[inline]
-fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
-    if usize::BITS < 64 && alloc_size > isize::MAX as usize {
-        Err(CapacityOverflow.into())
-    } else {
-        Ok(())
-    }
-}
-
 #[inline]
 fn layout_array(cap: usize, elem_layout: Layout) -> Result<Layout, TryReserveError> {
     elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into())
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 22cdd8ecde0..e772ac25a95 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -418,9 +418,8 @@ impl str {
         }
 
         fn case_ignorable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
-            use core::unicode::{Case_Ignorable, Cased};
-            match iter.skip_while(|&c| Case_Ignorable(c)).next() {
-                Some(c) => Cased(c),
+            match iter.skip_while(|&c| c.is_case_ignorable()).next() {
+                Some(c) => c.is_cased(),
                 None => false,
             }
         }
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 4cdc046f71e..d14419a23a1 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -48,6 +48,7 @@ pub use iter::IntoIter;
 /// assert_eq!(strings, ["Hello there!", "Hello there!"]);
 /// ```
 #[inline]
+#[must_use = "cloning is often expensive and is not expected to have side effects"]
 #[stable(feature = "array_repeat", since = "CURRENT_RUSTC_VERSION")]
 pub fn repeat<T: Clone, const N: usize>(val: T) -> [T; N] {
     from_trusted_iterator(repeat_n(val, N))
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index 6ce7e4656b9..78ba69fec14 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -154,9 +154,8 @@
 /// [`String`]: ../../std/string/struct.String.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Borrow"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub trait Borrow<Borrowed: ?Sized> {
+pub const trait Borrow<Borrowed: ?Sized> {
     /// Immutably borrows from an owned value.
     ///
     /// # Examples
@@ -187,9 +186,8 @@ pub trait Borrow<Borrowed: ?Sized> {
 /// for more information on borrowing as another type.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "BorrowMut"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
+pub const trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
     /// Mutably borrows from an owned value.
     ///
     /// # Examples
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 3336d028e27..76f54db2870 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -969,7 +969,43 @@ impl char {
     #[must_use]
     #[inline]
     pub(crate) fn is_grapheme_extended(self) -> bool {
-        unicode::Grapheme_Extend(self)
+        !self.is_ascii() && unicode::Grapheme_Extend(self)
+    }
+
+    /// Returns `true` if this `char` has the `Cased` property.
+    ///
+    /// `Cased` is described in Chapter 4 (Character Properties) of the [Unicode Standard] and
+    /// specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`].
+    ///
+    /// [Unicode Standard]: https://www.unicode.org/versions/latest/
+    /// [ucd]: https://www.unicode.org/reports/tr44/
+    /// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
+    #[must_use]
+    #[inline]
+    #[doc(hidden)]
+    #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
+    pub fn is_cased(self) -> bool {
+        if self.is_ascii() { self.is_ascii_alphabetic() } else { unicode::Cased(self) }
+    }
+
+    /// Returns `true` if this `char` has the `Case_Ignorable` property.
+    ///
+    /// `Case_Ignorable` is described in Chapter 4 (Character Properties) of the [Unicode Standard] and
+    /// specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`].
+    ///
+    /// [Unicode Standard]: https://www.unicode.org/versions/latest/
+    /// [ucd]: https://www.unicode.org/reports/tr44/
+    /// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
+    #[must_use]
+    #[inline]
+    #[doc(hidden)]
+    #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
+    pub fn is_case_ignorable(self) -> bool {
+        if self.is_ascii() {
+            matches!(self, '\'' | '.' | ':' | '^' | '`')
+        } else {
+            unicode::Case_Ignorable(self)
+        }
     }
 
     /// Returns `true` if this `char` has one of the general categories for numbers.
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 0add77b2bc8..7f2a40f753f 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -191,8 +191,7 @@ mod uninit;
 #[rustc_diagnostic_item = "Clone"]
 #[rustc_trivial_field_reads]
 #[rustc_const_unstable(feature = "const_clone", issue = "142757")]
-#[const_trait]
-pub trait Clone: Sized {
+pub const trait Clone: Sized {
     /// Returns a duplicate of the value.
     ///
     /// Note that what "duplicate" means varies by type:
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index ab018fa2675..0812322f3fb 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -247,9 +247,8 @@ use crate::ops::ControlFlow;
     append_const_msg
 )]
 #[rustc_diagnostic_item = "PartialEq"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
-pub trait PartialEq<Rhs: PointeeSized = Self>: PointeeSized {
+pub const trait PartialEq<Rhs: PointeeSized = Self>: PointeeSized {
     /// Tests for `self` and `other` values to be equal, and is used by `==`.
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs
index a06a6e8b69a..2265fa7a353 100644
--- a/library/core/src/cmp/bytewise.rs
+++ b/library/core/src/cmp/bytewise.rs
@@ -17,7 +17,7 @@ use crate::num::NonZero;
 /// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct.
 /// - `<Self as PartialEq<Rhs>>::{eq,ne}` are equivalent to comparing the bytes.
 #[rustc_specialization_trait]
-#[const_trait]
+#[const_trait] // FIXME(const_trait_impl): Migrate to `const unsafe trait` once #146122 is fixed.
 pub(crate) unsafe trait BytewiseEq<Rhs = Self>:
     [const] PartialEq<Rhs> + Sized
 {
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index add21b491ad..a3cfd85974a 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -216,9 +216,8 @@ pub const fn identity<T>(x: T) -> T {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "AsRef"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub trait AsRef<T: PointeeSized>: PointeeSized {
+pub const trait AsRef<T: PointeeSized>: PointeeSized {
     /// Converts this type into a shared reference of the (usually inferred) input type.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_ref(&self) -> &T;
@@ -369,9 +368,8 @@ pub trait AsRef<T: PointeeSized>: PointeeSized {
 /// `&mut Vec<u8>`, for example, is the better choice (callers need to pass the correct type then).
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "AsMut"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub trait AsMut<T: PointeeSized>: PointeeSized {
+pub const trait AsMut<T: PointeeSized>: PointeeSized {
     /// Converts this type into a mutable reference of the (usually inferred) input type.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_mut(&mut self) -> &mut T;
@@ -450,8 +448,7 @@ pub trait AsMut<T: PointeeSized>: PointeeSized {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(search_unbox)]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-#[const_trait]
-pub trait Into<T>: Sized {
+pub const trait Into<T>: Sized {
     /// Converts this type into the (usually inferred) input type.
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -587,8 +584,7 @@ pub trait Into<T>: Sized {
 ))]
 #[doc(search_unbox)]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-#[const_trait]
-pub trait From<T>: Sized {
+pub const trait From<T>: Sized {
     /// Converts to this type from the input type.
     #[rustc_diagnostic_item = "from_fn"]
     #[must_use]
@@ -616,8 +612,7 @@ pub trait From<T>: Sized {
 #[rustc_diagnostic_item = "TryInto"]
 #[stable(feature = "try_from", since = "1.34.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-#[const_trait]
-pub trait TryInto<T>: Sized {
+pub const trait TryInto<T>: Sized {
     /// The type returned in the event of a conversion error.
     #[stable(feature = "try_from", since = "1.34.0")]
     type Error;
@@ -696,8 +691,7 @@ pub trait TryInto<T>: Sized {
 #[rustc_diagnostic_item = "TryFrom"]
 #[stable(feature = "try_from", since = "1.34.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-#[const_trait]
-pub trait TryFrom<T>: Sized {
+pub const trait TryFrom<T>: Sized {
     /// The type returned in the event of a conversion error.
     #[stable(feature = "try_from", since = "1.34.0")]
     type Error;
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index 897267968aa..1cc4fb6e8fd 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -33,7 +33,7 @@ use crate::ascii::Char as AsciiChar;
 /// }
 /// ```
 ///
-/// Now, you get all of the default values. Rust implements `Default` for various primitives types.
+/// Now, you get all of the default values. Rust implements `Default` for various primitive types.
 ///
 /// If you want to override a particular option, but still retain the other defaults:
 ///
@@ -103,9 +103,8 @@ use crate::ascii::Char as AsciiChar;
 /// ```
 #[rustc_diagnostic_item = "Default"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_default", issue = "143894")]
-pub trait Default: Sized {
+pub const trait Default: Sized {
     /// Returns the "default value" for a type.
     ///
     /// Default values are often some kind of initial value, identity value, or anything else that
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index 605ba42c541..253a7b7587e 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -3,7 +3,7 @@
 use crate::fmt::NumBuffer;
 use crate::mem::MaybeUninit;
 use crate::num::fmt as numfmt;
-use crate::{fmt, ptr, slice, str};
+use crate::{fmt, str};
 
 /// Formatting of integers with a non-decimal radix.
 macro_rules! radix_integer {
@@ -96,8 +96,8 @@ macro_rules! impl_Debug {
     };
 }
 
-// 2 digit decimal look up table
-static DEC_DIGITS_LUT: &[u8; 200] = b"\
+// The string of all two-digit numbers in range 00..99 is used as a lookup table.
+static DECIMAL_PAIRS: &[u8; 200] = b"\
       0001020304050607080910111213141516171819\
       2021222324252627282930313233343536373839\
       4041424344454647484950515253545556575859\
@@ -123,6 +123,9 @@ macro_rules! impl_Display {
 
         $(
         const _: () = {
+            assert!($Signed::MIN < 0, "need signed");
+            assert!($Unsigned::MIN == 0, "need unsigned");
+            assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
             assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
             assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
         };
@@ -207,10 +210,10 @@ macro_rules! impl_Display {
                     remain /= scale;
                     let pair1 = (quad / 100) as usize;
                     let pair2 = (quad % 100) as usize;
-                    buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
-                    buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
-                    buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
-                    buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
+                    buf[offset + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]);
+                    buf[offset + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]);
+                    buf[offset + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
+                    buf[offset + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
                 }
 
                 // Format per two digits from the lookup table.
@@ -225,8 +228,8 @@ macro_rules! impl_Display {
 
                     let pair = (remain % 100) as usize;
                     remain /= 100;
-                    buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
-                    buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
+                    buf[offset + 0].write(DECIMAL_PAIRS[pair * 2 + 0]);
+                    buf[offset + 1].write(DECIMAL_PAIRS[pair * 2 + 1]);
                 }
 
                 // Format the last remaining digit, if any.
@@ -242,7 +245,7 @@ macro_rules! impl_Display {
                     // Either the compiler sees that remain < 10, or it prevents
                     // a boundary check up next.
                     let last = (remain & 15) as usize;
-                    buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
+                    buf[offset].write(DECIMAL_PAIRS[last * 2 + 1]);
                     // not used: remain = 0;
                 }
 
@@ -335,7 +338,6 @@ macro_rules! impl_Display {
             }
         }
 
-
         )*
 
         #[cfg(feature = "optimize_for_size")]
@@ -374,178 +376,213 @@ macro_rules! impl_Display {
 
 macro_rules! impl_Exp {
     ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
+        const _: () = assert!($T::MIN == 0, "need unsigned");
+
         fn $fmt_fn(
-            mut n: $T,
+            f: &mut fmt::Formatter<'_>,
+            n: $T,
             is_nonnegative: bool,
-            upper: bool,
-            f: &mut fmt::Formatter<'_>
+            letter_e: u8
         ) -> fmt::Result {
-            let (mut n, mut exponent, trailing_zeros, added_precision) = {
-                let mut exponent = 0;
-                // count and remove trailing decimal zeroes
-                while n % 10 == 0 && n >= 10 {
-                    n /= 10;
-                    exponent += 1;
-                }
-                let (added_precision, subtracted_precision) = match f.precision() {
-                    Some(fmt_prec) => {
-                        // number of decimal digits minus 1
-                        let mut tmp = n;
-                        let mut prec = 0;
-                        while tmp >= 10 {
-                            tmp /= 10;
-                            prec += 1;
-                        }
-                        (fmt_prec.saturating_sub(prec), prec.saturating_sub(fmt_prec))
+            debug_assert!(letter_e.is_ascii_alphabetic(), "single-byte character");
+
+            // Print the integer as a coefficient in range (-10, 10).
+            let mut exp = n.checked_ilog10().unwrap_or(0) as usize;
+            debug_assert!(n / (10 as $T).pow(exp as u32) < 10);
+
+            // Precisison is counted as the number of digits in the fraction.
+            let mut coef_prec = exp;
+            // Keep the digits as an integer (paired with its coef_prec count).
+            let mut coef = n;
+
+            // A Formatter may set the precision to a fixed number of decimals.
+            let more_prec = match f.precision() {
+                None => {
+                    // Omit any and all trailing zeroes.
+                    while coef_prec != 0 && coef % 10 == 0 {
+                        coef /= 10;
+                        coef_prec -= 1;
                     }
-                    None => (0, 0)
-                };
-                for _ in 1..subtracted_precision {
-                    n /= 10;
-                    exponent += 1;
-                }
-                if subtracted_precision != 0 {
-                    let rem = n % 10;
-                    n /= 10;
-                    exponent += 1;
-                    // round up last digit, round to even on a tie
-                    if rem > 5 || (rem == 5 && (n % 2 != 0 || subtracted_precision > 1 )) {
-                        n += 1;
-                        // if the digit is rounded to the next power
-                        // instead adjust the exponent
-                        if n.ilog10() > (n - 1).ilog10() {
-                            n /= 10;
-                            exponent += 1;
-                        }
+                    0
+                },
+
+                Some(fmt_prec) if fmt_prec >= coef_prec => {
+                    // Count the number of additional zeroes needed.
+                    fmt_prec - coef_prec
+                },
+
+                Some(fmt_prec) => {
+                    // Count the number of digits to drop.
+                    let less_prec = coef_prec - fmt_prec;
+                    assert!(less_prec > 0);
+                    // Scale down the coefficient/precision pair. For example,
+                    // coef 123456 gets coef_prec 5 (to make 1.23456). To format
+                    // the number with 2 decimals, i.e., fmt_prec 2, coef should
+                    // be scaled by 10⁵⁻²=1000 to get coef 123 with coef_prec 2.
+
+                    // SAFETY: Any precision less than coef_prec will cause a
+                    // power of ten below the coef value.
+                    let scale = unsafe {
+                        (10 as $T).checked_pow(less_prec as u32).unwrap_unchecked()
+                    };
+                    let floor = coef / scale;
+                    // Round half to even conform documentation.
+                    let over = coef % scale;
+                    let half = scale / 2;
+                    let round_up = if over < half {
+                        0
+                    } else if over > half {
+                        1
+                    } else {
+                        floor & 1 // round odd up to even
+                    };
+                    // Adding one to a scale down of at least 10 won't overflow.
+                    coef = floor + round_up;
+                    coef_prec = fmt_prec;
+
+                    // The round_up may have caused the coefficient to reach 10
+                    // (which is not permitted). For example, anything in range
+                    // [9.95, 10) becomes 10.0 when adjusted to precision 1.
+                    if round_up != 0 && coef.checked_ilog10().unwrap_or(0) as usize > coef_prec {
+                        debug_assert_eq!(coef, (10 as $T).pow(coef_prec as u32 + 1));
+                        coef /= 10; // drop one trailing zero
+                        exp += 1;   // one power of ten higher
                     }
-                }
-                (n, exponent, exponent, added_precision)
+                    0
+                },
             };
 
-            // Since `curr` always decreases by the number of digits copied, this means
-            // that `curr >= 0`.
-            let mut buf = [MaybeUninit::<u8>::uninit(); 40];
-            let mut curr = buf.len(); //index for buf
-            let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
-            let lut_ptr = DEC_DIGITS_LUT.as_ptr();
-
-            // decode 2 chars at a time
-            while n >= 100 {
-                let d1 = ((n % 100) as usize) << 1;
-                curr -= 2;
-                // SAFETY: `d1 <= 198`, so we can copy from `lut_ptr[d1..d1 + 2]` since
-                // `DEC_DIGITS_LUT` has a length of 200.
-                unsafe {
-                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
-                }
-                n /= 100;
-                exponent += 2;
-            }
-            // n is <= 99, so at most 2 chars long
-            let mut n = n as isize; // possibly reduce 64bit math
-            // decode second-to-last character
-            if n >= 10 {
-                curr -= 1;
-                // SAFETY: Safe since `40 > curr >= 0` (see comment)
-                unsafe {
-                    *buf_ptr.add(curr) = (n as u8 % 10_u8) + b'0';
+            // Allocate a text buffer with lazy initialization.
+            const MAX_DEC_N: usize = $T::MAX.ilog10() as usize + 1;
+            const MAX_COEF_LEN: usize = MAX_DEC_N + ".".len();
+            const MAX_TEXT_LEN: usize = MAX_COEF_LEN + "e99".len();
+            let mut buf = [MaybeUninit::<u8>::uninit(); MAX_TEXT_LEN];
+
+            // Encode the coefficient in buf[..coef_len].
+            let (lead_dec, coef_len) = if coef_prec == 0 && more_prec == 0 {
+                (coef, 1_usize) // single digit; no fraction
+            } else {
+                buf[1].write(b'.');
+                let fraction_range = 2..(2 + coef_prec);
+
+                // Consume the least-significant decimals from a working copy.
+                let mut remain = coef;
+                #[cfg(feature = "optimize_for_size")] {
+                    for i in fraction_range.clone().rev() {
+                        let digit = (remain % 10) as usize;
+                        remain /= 10;
+                        buf[i].write(b'0' + digit as u8);
+                    }
                 }
-                n /= 10;
-                exponent += 1;
-            }
-            // add decimal point iff >1 mantissa digit will be printed
-            if exponent != trailing_zeros || added_precision != 0 {
-                curr -= 1;
-                // SAFETY: Safe since `40 > curr >= 0`
-                unsafe {
-                    *buf_ptr.add(curr) = b'.';
+                #[cfg(not(feature = "optimize_for_size"))] {
+                    // Write digits per two at a time with a lookup table.
+                    for i in fraction_range.clone().skip(1).rev().step_by(2) {
+                        let pair = (remain % 100) as usize;
+                        remain /= 100;
+                        buf[i - 1].write(DECIMAL_PAIRS[pair * 2 + 0]);
+                        buf[i - 0].write(DECIMAL_PAIRS[pair * 2 + 1]);
+                    }
+                    // An odd number of digits leave one digit remaining.
+                    if coef_prec & 1 != 0 {
+                        let digit = (remain % 10) as usize;
+                        remain /= 10;
+                        buf[fraction_range.start].write(b'0' + digit as u8);
+                    }
                 }
-            }
 
-            // SAFETY: Safe since `40 > curr >= 0`
-            let buf_slice = unsafe {
-                // decode last character
-                curr -= 1;
-                *buf_ptr.add(curr) = (n as u8) + b'0';
-
-                let len = buf.len() - curr as usize;
-                slice::from_raw_parts(buf_ptr.add(curr), len)
+                (remain, fraction_range.end)
             };
-
-            // stores 'e' (or 'E') and the up to 2-digit exponent
-            let mut exp_buf = [MaybeUninit::<u8>::uninit(); 3];
-            let exp_ptr = MaybeUninit::slice_as_mut_ptr(&mut exp_buf);
-            // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]`
-            // is contained within `exp_buf` since `len <= 3`.
-            let exp_slice = unsafe {
-                *exp_ptr.add(0) = if upper { b'E' } else { b'e' };
-                let len = if exponent < 10 {
-                    *exp_ptr.add(1) = (exponent as u8) + b'0';
-                    2
-                } else {
-                    let off = exponent << 1;
-                    ptr::copy_nonoverlapping(lut_ptr.add(off), exp_ptr.add(1), 2);
-                    3
-                };
-                slice::from_raw_parts(exp_ptr, len)
+            debug_assert!(lead_dec < 10);
+            debug_assert!(lead_dec != 0 || coef == 0, "significant digits only");
+            buf[0].write(b'0' + lead_dec as u8);
+
+            // SAFETY: The number of decimals is limited, captured by MAX.
+            unsafe { core::hint::assert_unchecked(coef_len <= MAX_COEF_LEN) }
+            // Encode the scale factor in buf[coef_len..text_len].
+            buf[coef_len].write(letter_e);
+            let text_len: usize = match exp {
+                ..10 => {
+                    buf[coef_len + 1].write(b'0' + exp as u8);
+                    coef_len + 2
+                },
+                10..100 => {
+                    #[cfg(feature = "optimize_for_size")] {
+                        buf[coef_len + 1].write(b'0' + (exp / 10) as u8);
+                        buf[coef_len + 2].write(b'0' + (exp % 10) as u8);
+                    }
+                    #[cfg(not(feature = "optimize_for_size"))] {
+                        buf[coef_len + 1].write(DECIMAL_PAIRS[exp * 2 + 0]);
+                        buf[coef_len + 2].write(DECIMAL_PAIRS[exp * 2 + 1]);
+                    }
+                    coef_len + 3
+                },
+                _ => {
+                    const { assert!($T::MAX.ilog10() < 100) };
+                    // SAFETY: A `u256::MAX` would get exponent 77.
+                    unsafe { core::hint::unreachable_unchecked() }
+                }
             };
-
-            let parts = &[
-                numfmt::Part::Copy(buf_slice),
-                numfmt::Part::Zero(added_precision),
-                numfmt::Part::Copy(exp_slice),
-            ];
-            let sign = if !is_nonnegative {
-                "-"
-            } else if f.sign_plus() {
-                "+"
+            // SAFETY: All bytes up until text_len have been set.
+            let text = unsafe { buf[..text_len].assume_init_ref() };
+
+            if more_prec == 0 {
+                // SAFETY: Text is set with ASCII exclusively: either a decimal,
+                // or a LETTER_E, or a dot. ASCII implies valid UTF-8.
+                let as_str = unsafe { str::from_utf8_unchecked(text) };
+                f.pad_integral(is_nonnegative, "", as_str)
             } else {
-                ""
-            };
-            let formatted = numfmt::Formatted { sign, parts };
-            // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters.
-            unsafe { f.pad_formatted_parts(&formatted) }
+                let parts = &[
+                    numfmt::Part::Copy(&text[..coef_len]),
+                    numfmt::Part::Zero(more_prec),
+                    numfmt::Part::Copy(&text[coef_len..]),
+                ];
+                let sign = if !is_nonnegative {
+                    "-"
+                } else if f.sign_plus() {
+                    "+"
+                } else {
+                    ""
+                };
+                // SAFETY: Text is set with ASCII exclusively: either a decimal,
+                // or a LETTER_E, or a dot. ASCII implies valid UTF-8.
+                unsafe { f.pad_formatted_parts(&numfmt::Formatted { sign, parts }) }
+            }
         }
 
         $(
-            #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::LowerExp for $Signed {
-                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                    let is_nonnegative = *self >= 0;
-                    let n = if is_nonnegative {
-                        *self as $T
-                    } else {
-                        self.unsigned_abs() as $T
-                    };
-                    $fmt_fn(n, is_nonnegative, false, f)
-                }
+        const _: () = {
+            assert!($Signed::MIN < 0, "need signed");
+            assert!($Unsigned::MIN == 0, "need unsigned");
+            assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
+            assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
+            assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
+        };
+        #[stable(feature = "integer_exp_format", since = "1.42.0")]
+        impl fmt::LowerExp for $Signed {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                $fmt_fn(f, self.unsigned_abs() as $T, *self >= 0, b'e')
             }
-            #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::LowerExp for $Unsigned {
-                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                    $fmt_fn(*self as $T, true, false, f)
-                }
-            })*
-
-        $(
-            #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::UpperExp for $Signed {
-                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                    let is_nonnegative = *self >= 0;
-                    let n = if is_nonnegative {
-                        *self as $T
-                    } else {
-                        self.unsigned_abs() as $T
-                    };
-                    $fmt_fn(n, is_nonnegative, true, f)
-                }
+        }
+        #[stable(feature = "integer_exp_format", since = "1.42.0")]
+        impl fmt::LowerExp for $Unsigned {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                $fmt_fn(f, *self as $T, true, b'e')
             }
-            #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::UpperExp for $Unsigned {
-                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                    $fmt_fn(*self as $T, true, true, f)
-                }
-            })*
+        }
+        #[stable(feature = "integer_exp_format", since = "1.42.0")]
+        impl fmt::UpperExp for $Signed {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                $fmt_fn(f, self.unsigned_abs() as $T, *self >= 0, b'E')
+            }
+        }
+        #[stable(feature = "integer_exp_format", since = "1.42.0")]
+        impl fmt::UpperExp for $Unsigned {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                $fmt_fn(f, *self as $T, true, b'E')
+            }
+        }
+        )*
+
     };
 }
 
@@ -658,10 +695,10 @@ impl u128 {
             remain /= 1_00_00;
             let pair1 = (quad / 100) as usize;
             let pair2 = (quad % 100) as usize;
-            buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
-            buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
-            buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
-            buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
+            buf[offset + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]);
+            buf[offset + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]);
+            buf[offset + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
+            buf[offset + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
         }
 
         // Format per two digits from the lookup table.
@@ -676,8 +713,8 @@ impl u128 {
 
             let pair = (remain % 100) as usize;
             remain /= 100;
-            buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
-            buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
+            buf[offset + 0].write(DECIMAL_PAIRS[pair * 2 + 0]);
+            buf[offset + 1].write(DECIMAL_PAIRS[pair * 2 + 1]);
         }
 
         // Format the last remaining digit, if any.
@@ -693,7 +730,7 @@ impl u128 {
             // Either the compiler sees that remain < 10, or it prevents
             // a boundary check up next.
             let last = (remain & 15) as usize;
-            buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
+            buf[offset].write(DECIMAL_PAIRS[last * 2 + 1]);
             // not used: remain = 0;
         }
         offset
@@ -792,10 +829,10 @@ fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
         remain /= 1_00_00;
         let pair1 = (quad / 100) as usize;
         let pair2 = (quad % 100) as usize;
-        buf[quad_index * 4 + OFFSET + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
-        buf[quad_index * 4 + OFFSET + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
-        buf[quad_index * 4 + OFFSET + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
-        buf[quad_index * 4 + OFFSET + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
+        buf[quad_index * 4 + OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]);
+        buf[quad_index * 4 + OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]);
+        buf[quad_index * 4 + OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
+        buf[quad_index * 4 + OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
     }
 }
 
diff --git a/library/core/src/intrinsics/fallback.rs b/library/core/src/intrinsics/fallback.rs
index eec5c4d646d..932537f2581 100644
--- a/library/core/src/intrinsics/fallback.rs
+++ b/library/core/src/intrinsics/fallback.rs
@@ -7,9 +7,8 @@
 )]
 #![allow(missing_docs)]
 
-#[const_trait]
 #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
-pub trait CarryingMulAdd: Copy + 'static {
+pub const trait CarryingMulAdd: Copy + 'static {
     type Unsigned: Copy + 'static;
     fn carrying_mul_add(
         self,
@@ -111,9 +110,8 @@ impl const CarryingMulAdd for i128 {
     }
 }
 
-#[const_trait]
 #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
-pub trait DisjointBitOr: Copy + 'static {
+pub const trait DisjointBitOr: Copy + 'static {
     /// See [`super::disjoint_bitor`]; we just need the trait indirection to handle
     /// different types since calling intrinsics with generics doesn't work.
     unsafe fn disjoint_bitor(self, other: Self) -> Self;
@@ -148,3 +146,75 @@ impl_disjoint_bitor! {
     u8, u16, u32, u64, u128, usize,
     i8, i16, i32, i64, i128, isize,
 }
+
+#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
+pub const trait FunnelShift: Copy + 'static {
+    /// See [`super::unchecked_funnel_shl`]; we just need the trait indirection to handle
+    /// different types since calling intrinsics with generics doesn't work.
+    unsafe fn unchecked_funnel_shl(self, rhs: Self, shift: u32) -> Self;
+
+    /// See [`super::unchecked_funnel_shr`]; we just need the trait indirection to handle
+    /// different types since calling intrinsics with generics doesn't work.
+    unsafe fn unchecked_funnel_shr(self, rhs: Self, shift: u32) -> Self;
+}
+
+macro_rules! impl_funnel_shifts {
+    ($($type:ident),*) => {$(
+        #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
+        impl const FunnelShift for $type {
+            #[cfg_attr(miri, track_caller)]
+            #[inline]
+            unsafe fn unchecked_funnel_shl(self, rhs: Self, shift: u32) -> Self {
+                // This implementation is also used by Miri so we have to check the precondition.
+                // SAFETY: this is guaranteed by the caller
+                unsafe { super::assume(shift < $type::BITS) };
+                if shift == 0 {
+                    self
+                } else {
+                    // SAFETY:
+                    //  - `shift < T::BITS`, which satisfies `unchecked_shl`
+                    //  - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
+                    //    above), which satisfies `unchecked_shr`
+                    //  - because the types are unsigned, the combination are disjoint bits (this is
+                    //    not true if they're signed, since SHR will fill in the empty space with a
+                    //    sign bit, not zero)
+                    unsafe {
+                        super::disjoint_bitor(
+                            super::unchecked_shl(self, shift),
+                            super::unchecked_shr(rhs, $type::BITS - shift),
+                        )
+                    }
+                }
+            }
+
+            #[cfg_attr(miri, track_caller)]
+            #[inline]
+            unsafe fn unchecked_funnel_shr(self, rhs: Self, shift: u32) -> Self {
+                // This implementation is also used by Miri so we have to check the precondition.
+                // SAFETY: this is guaranteed by the caller
+                unsafe { super::assume(shift < $type::BITS) };
+                if shift == 0 {
+                    rhs
+                } else {
+                    // SAFETY:
+                    //  - `shift < T::BITS`, which satisfies `unchecked_shr`
+                    //  - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
+                    //    above), which satisfies `unchecked_shl`
+                    //  - because the types are unsigned, the combination are disjoint bits (this is
+                    //    not true if they're signed, since SHR will fill in the empty space with a
+                    //    sign bit, not zero)
+                    unsafe {
+                        super::disjoint_bitor(
+                            super::unchecked_shl(self, $type::BITS - shift),
+                            super::unchecked_shr(rhs, shift),
+                        )
+                    }
+                }
+            }
+        }
+    )*};
+}
+
+impl_funnel_shifts! {
+    u8, u16, u32, u64, u128, usize
+}
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 904aa52c784..bffffbc29c1 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -2102,6 +2102,61 @@ pub const fn saturating_add<T: Copy>(a: T, b: T) -> T;
 #[rustc_intrinsic]
 pub const fn saturating_sub<T: Copy>(a: T, b: T) -> T;
 
+/// Funnel Shift left.
+///
+/// Concatenates `a` and `b` (with `a` in the most significant half),
+/// creating an integer twice as wide. Then shift this integer left
+/// by `shift`), and extract the most significant half. If `a` and `b`
+/// are the same, this is equivalent to a rotate left operation.
+///
+/// It is undefined behavior if `shift` is greater than or equal to the
+/// bit size of `T`.
+///
+/// Safe versions of this intrinsic are available on the integer primitives
+/// via the `funnel_shl` method. For example, [`u32::funnel_shl`].
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+#[unstable(feature = "funnel_shifts", issue = "145686")]
+#[track_caller]
+#[miri::intrinsic_fallback_is_spec]
+pub const unsafe fn unchecked_funnel_shl<T: [const] fallback::FunnelShift>(
+    a: T,
+    b: T,
+    shift: u32,
+) -> T {
+    // SAFETY: caller ensures that `shift` is in-range
+    unsafe { a.unchecked_funnel_shl(b, shift) }
+}
+
+/// Funnel Shift right.
+///
+/// Concatenates `a` and `b` (with `a` in the most significant half),
+/// creating an integer twice as wide. Then shift this integer right
+/// by `shift` (taken modulo the bit size of `T`), and extract the
+/// least significant half. If `a` and `b` are the same, this is equivalent
+/// to a rotate right operation.
+///
+/// It is undefined behavior if `shift` is greater than or equal to the
+/// bit size of `T`.
+///
+/// Safer versions of this intrinsic are available on the integer primitives
+/// via the `funnel_shr` method. For example, [`u32::funnel_shr`]
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+#[unstable(feature = "funnel_shifts", issue = "145686")]
+#[track_caller]
+#[miri::intrinsic_fallback_is_spec]
+pub const unsafe fn unchecked_funnel_shr<T: [const] fallback::FunnelShift>(
+    a: T,
+    b: T,
+    shift: u32,
+) -> T {
+    // SAFETY: caller ensures that `shift` is in-range
+    unsafe { a.unchecked_funnel_shr(b, shift) }
+}
+
 /// This is an implementation detail of [`crate::ptr::read`] and should
 /// not be used anywhere else.  See its comments for why this exists.
 ///
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index 943b88e2330..3ebdf7b4727 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -321,6 +321,7 @@ impl<A: Default, B: Default> Default for Chain<A, B> {
     ///
     /// // take requires `Default`
     /// let _: Chain<_, _> = mem::take(&mut foo.0);
+    /// ```
     fn default() -> Self {
         Chain::new(Default::default(), Default::default())
     }
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs
index a6522659620..a55de75d56c 100644
--- a/library/core/src/iter/adapters/peekable.rs
+++ b/library/core/src/iter/adapters/peekable.rs
@@ -317,6 +317,108 @@ impl<I: Iterator> Peekable<I> {
     {
         self.next_if(|next| next == expected)
     }
+
+    /// Consumes the next value of this iterator and applies a function `f` on it,
+    /// returning the result if the closure returns `Ok`.
+    ///
+    /// Otherwise if the closure returns `Err` the value is put back for the next iteration.
+    ///
+    /// The content of the `Err` variant is typically the original value of the closure,
+    /// but this is not required. If a different value is returned,
+    /// the next `peek()` or `next()` call will result in this new value.
+    /// This is similar to modifying the output of `peek_mut()`.
+    ///
+    /// If the closure panics, the next value will always be consumed and dropped
+    /// even if the panic is caught, because the closure never returned an `Err` value to put back.
+    ///
+    /// # Examples
+    ///
+    /// Parse the leading decimal number from an iterator of characters.
+    /// ```
+    /// #![feature(peekable_next_if_map)]
+    /// let mut iter = "125 GOTO 10".chars().peekable();
+    /// let mut line_num = 0_u32;
+    /// while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) {
+    ///     line_num = line_num * 10 + digit;
+    /// }
+    /// assert_eq!(line_num, 125);
+    /// assert_eq!(iter.collect::<String>(), " GOTO 10");
+    /// ```
+    ///
+    /// Matching custom types.
+    /// ```
+    /// #![feature(peekable_next_if_map)]
+    ///
+    /// #[derive(Debug, PartialEq, Eq)]
+    /// enum Node {
+    ///     Comment(String),
+    ///     Red(String),
+    ///     Green(String),
+    ///     Blue(String),
+    /// }
+    ///
+    /// /// Combines all consecutive `Comment` nodes into a single one.
+    /// fn combine_comments(nodes: Vec<Node>) -> Vec<Node> {
+    ///     let mut result = Vec::with_capacity(nodes.len());
+    ///     let mut iter = nodes.into_iter().peekable();
+    ///     let mut comment_text = None::<String>;
+    ///     loop {
+    ///         // Typically the closure in .next_if_map() matches on the input,
+    ///         //  extracts the desired pattern into an `Ok`,
+    ///         //  and puts the rest into an `Err`.
+    ///         while let Some(text) = iter.next_if_map(|node| match node {
+    ///             Node::Comment(text) => Ok(text),
+    ///             other => Err(other),
+    ///         }) {
+    ///             comment_text.get_or_insert_default().push_str(&text);
+    ///         }
+    ///
+    ///         if let Some(text) = comment_text.take() {
+    ///             result.push(Node::Comment(text));
+    ///         }
+    ///         if let Some(node) = iter.next() {
+    ///             result.push(node);
+    ///         } else {
+    ///             break;
+    ///         }
+    ///     }
+    ///     result
+    /// }
+    ///# assert_eq!( // hiding the test to avoid cluttering the documentation.
+    ///#     combine_comments(vec![
+    ///#         Node::Comment("The".to_owned()),
+    ///#         Node::Comment("Quick".to_owned()),
+    ///#         Node::Comment("Brown".to_owned()),
+    ///#         Node::Red("Fox".to_owned()),
+    ///#         Node::Green("Jumped".to_owned()),
+    ///#         Node::Comment("Over".to_owned()),
+    ///#         Node::Blue("The".to_owned()),
+    ///#         Node::Comment("Lazy".to_owned()),
+    ///#         Node::Comment("Dog".to_owned()),
+    ///#     ]),
+    ///#     vec![
+    ///#         Node::Comment("TheQuickBrown".to_owned()),
+    ///#         Node::Red("Fox".to_owned()),
+    ///#         Node::Green("Jumped".to_owned()),
+    ///#         Node::Comment("Over".to_owned()),
+    ///#         Node::Blue("The".to_owned()),
+    ///#         Node::Comment("LazyDog".to_owned()),
+    ///#     ],
+    ///# )
+    /// ```
+    #[unstable(feature = "peekable_next_if_map", issue = "143702")]
+    pub fn next_if_map<R>(&mut self, f: impl FnOnce(I::Item) -> Result<R, I::Item>) -> Option<R> {
+        let unpeek = if let Some(item) = self.next() {
+            match f(item) {
+                Ok(result) => return Some(result),
+                Err(item) => Some(item),
+            }
+        } else {
+            None
+        };
+        self.peeked = Some(unpeek);
+        None
+    }
 }
 
 #[unstable(feature = "trusted_len", issue = "37572")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 82506379cac..c306011bdda 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -156,6 +156,7 @@
 #![feature(f128)]
 #![feature(freeze_impls)]
 #![feature(fundamental)]
+#![feature(funnel_shifts)]
 #![feature(if_let_guard)]
 #![feature(intra_doc_pointers)]
 #![feature(intrinsics)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 73aad27afef..d03d7a43469 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1057,8 +1057,7 @@ marker_impls! {
 #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
 #[rustc_deny_explicit_impl]
 #[rustc_do_not_implement_via_object]
-#[const_trait]
-pub trait Destruct {}
+pub const trait Destruct {}
 
 /// A marker for tuple types.
 ///
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 4282b1af9f2..66c892aadd0 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -832,7 +832,6 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn midpoint(self, other: f128) -> f128 {
-        const LO: f128 = f128::MIN_POSITIVE * 2.;
         const HI: f128 = f128::MAX / 2.;
 
         let (a, b) = (self, other);
@@ -842,14 +841,7 @@ impl f128 {
         if abs_a <= HI && abs_b <= HI {
             // Overflow is impossible
             (a + b) / 2.
-        } else if abs_a < LO {
-            // Not safe to halve `a` (would underflow)
-            a + (b / 2.)
-        } else if abs_b < LO {
-            // Not safe to halve `b` (would underflow)
-            (a / 2.) + b
         } else {
-            // Safe to halve `a` and `b`
             (a / 2.) + (b / 2.)
         }
     }
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 23a8661c14b..81220065e72 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -820,7 +820,6 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn midpoint(self, other: f16) -> f16 {
-        const LO: f16 = f16::MIN_POSITIVE * 2.;
         const HI: f16 = f16::MAX / 2.;
 
         let (a, b) = (self, other);
@@ -830,14 +829,7 @@ impl f16 {
         if abs_a <= HI && abs_b <= HI {
             // Overflow is impossible
             (a + b) / 2.
-        } else if abs_a < LO {
-            // Not safe to halve `a` (would underflow)
-            a + (b / 2.)
-        } else if abs_b < LO {
-            // Not safe to halve `b` (would underflow)
-            (a / 2.) + b
         } else {
-            // Safe to halve `a` and `b`
             (a / 2.) + (b / 2.)
         }
     }
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index da08bfc5950..cefcf1d1fe2 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1025,7 +1025,6 @@ impl f32 {
                 ((self as f64 + other as f64) / 2.0) as f32
             }
             _ => {
-                const LO: f32 = f32::MIN_POSITIVE * 2.;
                 const HI: f32 = f32::MAX / 2.;
 
                 let (a, b) = (self, other);
@@ -1035,14 +1034,7 @@ impl f32 {
                 if abs_a <= HI && abs_b <= HI {
                     // Overflow is impossible
                     (a + b) / 2.
-                } else if abs_a < LO {
-                    // Not safe to halve `a` (would underflow)
-                    a + (b / 2.)
-                } else if abs_b < LO {
-                    // Not safe to halve `b` (would underflow)
-                    (a / 2.) + b
                 } else {
-                    // Safe to halve `a` and `b`
                     (a / 2.) + (b / 2.)
                 }
             }
@@ -1954,8 +1946,8 @@ pub mod math {
     /// let abs_difference_x = (f32::math::abs_sub(x, 1.0) - 2.0).abs();
     /// let abs_difference_y = (f32::math::abs_sub(y, 1.0) - 0.0).abs();
     ///
-    /// assert!(abs_difference_x <= f32::EPSILON);
-    /// assert!(abs_difference_y <= f32::EPSILON);
+    /// assert!(abs_difference_x <= 1e-6);
+    /// assert!(abs_difference_y <= 1e-6);
     /// ```
     ///
     /// _This standalone function is for testing only.
@@ -2000,7 +1992,7 @@ pub mod math {
     /// // x^(1/3) - 2 == 0
     /// let abs_difference = (f32::math::cbrt(x) - 2.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     ///
     /// _This standalone function is for testing only.
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index dc0977cb147..9dd1141e703 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1026,7 +1026,6 @@ impl f64 {
     #[stable(feature = "num_midpoint", since = "1.85.0")]
     #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")]
     pub const fn midpoint(self, other: f64) -> f64 {
-        const LO: f64 = f64::MIN_POSITIVE * 2.;
         const HI: f64 = f64::MAX / 2.;
 
         let (a, b) = (self, other);
@@ -1036,14 +1035,7 @@ impl f64 {
         if abs_a <= HI && abs_b <= HI {
             // Overflow is impossible
             (a + b) / 2.
-        } else if abs_a < LO {
-            // Not safe to halve `a` (would underflow)
-            a + (b / 2.)
-        } else if abs_b < LO {
-            // Not safe to halve `b` (would underflow)
-            (a / 2.) + b
         } else {
-            // Safe to halve `a` and `b`
             (a / 2.) + (b / 2.)
         }
     }
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 25864db5fea..64a3dd3e8bc 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1285,7 +1285,7 @@ macro_rules! int_impl {
         ///
         /// ```should_panic
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")]
-        ///
+        /// ```
         #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
@@ -1413,6 +1413,66 @@ macro_rules! int_impl {
             }
         }
 
+        /// Exact shift left. Computes `self << rhs` as long as it can be reversed losslessly.
+        ///
+        /// Returns `None` if any bits that would be shifted out differ from the resulting sign bit
+        /// or if `rhs` >=
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        /// Otherwise, returns `Some(self << rhs)`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(exact_bitshifts)]
+        ///
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 2), Some(1 << ", stringify!($SelfT), "::BITS - 2));")]
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 1), None);")]
+        #[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 2), Some(-0x2 << ", stringify!($SelfT), "::BITS - 2));")]
+        #[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 1), None);")]
+        /// ```
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
+            if rhs < self.leading_zeros() || rhs < self.leading_ones() {
+                // SAFETY: rhs is checked above
+                Some(unsafe { self.unchecked_shl(rhs) })
+            } else {
+                None
+            }
+        }
+
+        /// Unchecked exact shift left. Computes `self << rhs`, assuming the operation can be
+        /// losslessly reversed and `rhs` cannot be larger than
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >=
+        /// self.leading_ones()` i.e. when
+        #[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
+        /// would return `None`.
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
+            assert_unsafe_precondition!(
+                check_language_ub,
+                concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out non-zero bits"),
+                (
+                    zeros: u32 = self.leading_zeros(),
+                    ones: u32 = self.leading_ones(),
+                    rhs: u32 = rhs,
+                ) => rhs < zeros || rhs < ones,
+            );
+
+            // SAFETY: this is guaranteed to be safe by the caller
+            unsafe { self.unchecked_shl(rhs) }
+        }
+
         /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
         /// larger than or equal to the number of bits in `self`.
         ///
@@ -1534,6 +1594,63 @@ macro_rules! int_impl {
             }
         }
 
+        /// Exact shift right. Computes `self >> rhs` as long as it can be reversed losslessly.
+        ///
+        /// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        /// Otherwise, returns `Some(self >> rhs)`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(exact_bitshifts)]
+        ///
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")]
+        /// ```
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
+            if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS {
+                // SAFETY: rhs is checked above
+                Some(unsafe { self.unchecked_shr(rhs) })
+            } else {
+                None
+            }
+        }
+
+        /// Unchecked exact shift right. Computes `self >> rhs`, assuming the operation can be
+        /// losslessly reversed and `rhs` cannot be larger than
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
+        #[doc = concat!(stringify!($SelfT), "::BITS`")]
+        /// i.e. when
+        #[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
+        /// would return `None`.
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
+            assert_unsafe_precondition!(
+                check_language_ub,
+                concat!(stringify!($SelfT), "::unchecked_exact_shr cannot shift out non-zero bits"),
+                (
+                    zeros: u32 = self.trailing_zeros(),
+                    bits: u32 =  <$SelfT>::BITS,
+                    rhs: u32 = rhs,
+                ) => rhs <= zeros && rhs < bits,
+            );
+
+            // SAFETY: this is guaranteed to be safe by the caller
+            unsafe { self.unchecked_shr(rhs) }
+        }
+
         /// Checked absolute value. Computes `self.abs()`, returning `None` if
         /// `self == MIN`.
         ///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 69c6a7dbd89..54d5a63633c 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -454,6 +454,9 @@ impl u8 {
         rot = 2,
         rot_op = "0x82",
         rot_result = "0xa",
+        fsh_op = "0x36",
+        fshl_result = "0x8",
+        fshr_result = "0x8d",
         swap_op = "0x12",
         swapped = "0x12",
         reversed = "0x48",
@@ -1088,6 +1091,9 @@ impl u16 {
         rot = 4,
         rot_op = "0xa003",
         rot_result = "0x3a",
+        fsh_op = "0x2de",
+        fshl_result = "0x30",
+        fshr_result = "0x302d",
         swap_op = "0x1234",
         swapped = "0x3412",
         reversed = "0x2c48",
@@ -1135,6 +1141,9 @@ impl u32 {
         rot = 8,
         rot_op = "0x10000b3",
         rot_result = "0xb301",
+        fsh_op = "0x2fe78e45",
+        fshl_result = "0xb32f",
+        fshr_result = "0xb32fe78e",
         swap_op = "0x12345678",
         swapped = "0x78563412",
         reversed = "0x1e6a2c48",
@@ -1158,6 +1167,9 @@ impl u64 {
         rot = 12,
         rot_op = "0xaa00000000006e1",
         rot_result = "0x6e10aa",
+        fsh_op = "0x2fe78e45983acd98",
+        fshl_result = "0x6e12fe",
+        fshr_result = "0x6e12fe78e45983ac",
         swap_op = "0x1234567890123456",
         swapped = "0x5634129078563412",
         reversed = "0x6a2c48091e6a2c48",
@@ -1181,6 +1193,9 @@ impl u128 {
         rot = 16,
         rot_op = "0x13f40000000000000000000000004f76",
         rot_result = "0x4f7613f4",
+        fsh_op = "0x2fe78e45983acd98039000008736273",
+        fshl_result = "0x4f7602fe",
+        fshr_result = "0x4f7602fe78e45983acd9803900000873",
         swap_op = "0x12345678901234567890123456789012",
         swapped = "0x12907856341290785634129078563412",
         reversed = "0x48091e6a2c48091e6a2c48091e6a2c48",
@@ -1207,6 +1222,9 @@ impl usize {
         rot = 4,
         rot_op = "0xa003",
         rot_result = "0x3a",
+        fsh_op = "0x2fe78e45983acd98039000008736273",
+        fshl_result = "0x4f7602fe",
+        fshr_result = "0x4f7602fe78e45983acd9803900000873",
         swap_op = "0x1234",
         swapped = "0x3412",
         reversed = "0x2c48",
@@ -1231,6 +1249,9 @@ impl usize {
         rot = 8,
         rot_op = "0x10000b3",
         rot_result = "0xb301",
+        fsh_op = "0x2fe78e45",
+        fshl_result = "0xb32f",
+        fshr_result = "0xb32fe78e",
         swap_op = "0x12345678",
         swapped = "0x78563412",
         reversed = "0x1e6a2c48",
@@ -1255,6 +1276,9 @@ impl usize {
         rot = 12,
         rot_op = "0xaa00000000006e1",
         rot_result = "0x6e10aa",
+        fsh_op = "0x2fe78e45983acd98",
+        fshl_result = "0x6e12fe",
+        fshr_result = "0x6e12fe78e45983ac",
         swap_op = "0x1234567890123456",
         swapped = "0x5634129078563412",
         reversed = "0x6a2c48091e6a2c48",
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index c1e656fdea2..bf72ec83197 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -14,6 +14,9 @@ macro_rules! uint_impl {
         rot = $rot:literal,
         rot_op = $rot_op:literal,
         rot_result = $rot_result:literal,
+        fsh_op = $fsh_op:literal,
+        fshl_result = $fshl_result:literal,
+        fshr_result = $fshr_result:literal,
         swap_op = $swap_op:literal,
         swapped = $swapped:literal,
         reversed = $reversed:literal,
@@ -375,6 +378,76 @@ macro_rules! uint_impl {
             return intrinsics::rotate_right(self, n);
         }
 
+        /// Performs a left funnel shift (concatenates `self` with `rhs`, with `self`
+        /// making up the most significant half, then shifts the combined value left
+        /// by `n`, and most significant half is extracted to produce the result).
+        ///
+        /// Please note this isn't the same operation as the `<<` shifting operator or
+        /// [`rotate_left`](Self::rotate_left), although `a.funnel_shl(a, n)` is *equivalent*
+        /// to `a.rotate_left(n)`.
+        ///
+        /// # Panics
+        ///
+        /// If `n` is greater than or equal to the number of bits in `self`
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(funnel_shifts)]
+        #[doc = concat!("let a = ", $rot_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let b = ", $fsh_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $fshl_result, ";")]
+        ///
+        #[doc = concat!("assert_eq!(a.funnel_shl(b, ", $rot, "), m);")]
+        /// ```
+        #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+        #[unstable(feature = "funnel_shifts", issue = "145686")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn funnel_shl(self, rhs: Self, n: u32) -> Self {
+            assert!(n < Self::BITS, "attempt to funnel shift left with overflow");
+            // SAFETY: just checked that `shift` is in-range
+            unsafe { intrinsics::unchecked_funnel_shl(self, rhs, n) }
+        }
+
+        /// Performs a right funnel shift (concatenates `self` and `rhs`, with `self`
+        /// making up the most significant half, then shifts the combined value right
+        /// by `n`, and least significant half is extracted to produce the result).
+        ///
+        /// Please note this isn't the same operation as the `>>` shifting operator or
+        /// [`rotate_right`](Self::rotate_right), although `a.funnel_shr(a, n)` is *equivalent*
+        /// to `a.rotate_right(n)`.
+        ///
+        /// # Panics
+        ///
+        /// If `n` is greater than or equal to the number of bits in `self`
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(funnel_shifts)]
+        #[doc = concat!("let a = ", $rot_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let b = ", $fsh_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $fshr_result, ";")]
+        ///
+        #[doc = concat!("assert_eq!(a.funnel_shr(b, ", $rot, "), m);")]
+        /// ```
+        #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+        #[unstable(feature = "funnel_shifts", issue = "145686")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn funnel_shr(self, rhs: Self, n: u32) -> Self {
+            assert!(n < Self::BITS, "attempt to funnel shift right with overflow");
+            // SAFETY: just checked that `shift` is in-range
+            unsafe { intrinsics::unchecked_funnel_shr(self, rhs, n) }
+        }
+
         /// Reverses the byte order of the integer.
         ///
         /// # Examples
@@ -1620,7 +1693,7 @@ macro_rules! uint_impl {
         ///
         /// ```should_panic
         #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")]
-        ///
+        /// ```
         #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
@@ -1748,6 +1821,63 @@ macro_rules! uint_impl {
             }
         }
 
+        /// Exact shift left. Computes `self << rhs` as long as it can be reversed losslessly.
+        ///
+        /// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        /// Otherwise, returns `Some(self << rhs)`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(exact_bitshifts)]
+        ///
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
+        /// ```
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
+            if rhs <= self.leading_zeros() && rhs < <$SelfT>::BITS {
+                // SAFETY: rhs is checked above
+                Some(unsafe { self.unchecked_shl(rhs) })
+            } else {
+                None
+            }
+        }
+
+        /// Unchecked exact shift left. Computes `self << rhs`, assuming the operation can be
+        /// losslessly reversed `rhs` cannot be larger than
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when `rhs > self.leading_zeros() || rhs >=
+        #[doc = concat!(stringify!($SelfT), "::BITS`")]
+        /// i.e. when
+        #[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
+        /// would return `None`.
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
+            assert_unsafe_precondition!(
+                check_language_ub,
+                concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
+                (
+                    zeros: u32 = self.leading_zeros(),
+                    bits: u32 =  <$SelfT>::BITS,
+                    rhs: u32 = rhs,
+                ) => rhs <= zeros && rhs < bits,
+            );
+
+            // SAFETY: this is guaranteed to be safe by the caller
+            unsafe { self.unchecked_shl(rhs) }
+        }
+
         /// Checked shift right. Computes `self >> rhs`, returning `None`
         /// if `rhs` is larger than or equal to the number of bits in `self`.
         ///
@@ -1863,6 +1993,63 @@ macro_rules! uint_impl {
             }
         }
 
+        /// Exact shift right. Computes `self >> rhs` as long as it can be reversed losslessly.
+        ///
+        /// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        /// Otherwise, returns `Some(self >> rhs)`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(exact_bitshifts)]
+        ///
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")]
+        /// ```
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
+            if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS {
+                // SAFETY: rhs is checked above
+                Some(unsafe { self.unchecked_shr(rhs) })
+            } else {
+                None
+            }
+        }
+
+        /// Unchecked exact shift right. Computes `self >> rhs`, assuming the operation can be
+        /// losslessly reversed and `rhs` cannot be larger than
+        #[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
+        #[doc = concat!(stringify!($SelfT), "::BITS`")]
+        /// i.e. when
+        #[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
+        /// would return `None`.
+        #[unstable(feature = "exact_bitshifts", issue = "144336")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
+            assert_unsafe_precondition!(
+                check_language_ub,
+                concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
+                (
+                    zeros: u32 = self.trailing_zeros(),
+                    bits: u32 =  <$SelfT>::BITS,
+                    rhs: u32 = rhs,
+                ) => rhs <= zeros && rhs < bits,
+            );
+
+            // SAFETY: this is guaranteed to be safe by the caller
+            unsafe { self.unchecked_shr(rhs) }
+        }
+
         /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
         /// overflow occurred.
         ///
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 16c719b0c39..6c6479c9984 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -74,8 +74,7 @@
     append_const_msg
 )]
 #[doc(alias = "+")]
-#[const_trait]
-pub trait Add<Rhs = Self> {
+pub const trait Add<Rhs = Self> {
     /// The resulting type after applying the `+` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -188,8 +187,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128
     append_const_msg
 )]
 #[doc(alias = "-")]
-#[const_trait]
-pub trait Sub<Rhs = Self> {
+pub const trait Sub<Rhs = Self> {
     /// The resulting type after applying the `-` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -323,8 +321,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128
     label = "no implementation for `{Self} * {Rhs}`"
 )]
 #[doc(alias = "*")]
-#[const_trait]
-pub trait Mul<Rhs = Self> {
+pub const trait Mul<Rhs = Self> {
     /// The resulting type after applying the `*` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -462,8 +459,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128
     label = "no implementation for `{Self} / {Rhs}`"
 )]
 #[doc(alias = "/")]
-#[const_trait]
-pub trait Div<Rhs = Self> {
+pub const trait Div<Rhs = Self> {
     /// The resulting type after applying the `/` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -572,8 +568,7 @@ div_impl_float! { f16 f32 f64 f128 }
     label = "no implementation for `{Self} % {Rhs}`"
 )]
 #[doc(alias = "%")]
-#[const_trait]
-pub trait Rem<Rhs = Self> {
+pub const trait Rem<Rhs = Self> {
     /// The resulting type after applying the `%` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -694,8 +689,7 @@ rem_impl_float! { f16 f32 f64 f128 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[doc(alias = "-")]
-#[const_trait]
-pub trait Neg {
+pub const trait Neg {
     /// The resulting type after applying the `-` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -772,8 +766,7 @@ neg_impl! { isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 )]
 #[doc(alias = "+")]
 #[doc(alias = "+=")]
-#[const_trait]
-pub trait AddAssign<Rhs = Self> {
+pub const trait AddAssign<Rhs = Self> {
     /// Performs the `+=` operation.
     ///
     /// # Example
@@ -844,8 +837,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 )]
 #[doc(alias = "-")]
 #[doc(alias = "-=")]
-#[const_trait]
-pub trait SubAssign<Rhs = Self> {
+pub const trait SubAssign<Rhs = Self> {
     /// Performs the `-=` operation.
     ///
     /// # Example
@@ -907,8 +899,7 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 )]
 #[doc(alias = "*")]
 #[doc(alias = "*=")]
-#[const_trait]
-pub trait MulAssign<Rhs = Self> {
+pub const trait MulAssign<Rhs = Self> {
     /// Performs the `*=` operation.
     ///
     /// # Example
@@ -970,8 +961,7 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 )]
 #[doc(alias = "/")]
 #[doc(alias = "/=")]
-#[const_trait]
-pub trait DivAssign<Rhs = Self> {
+pub const trait DivAssign<Rhs = Self> {
     /// Performs the `/=` operation.
     ///
     /// # Example
@@ -1036,8 +1026,7 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 )]
 #[doc(alias = "%")]
 #[doc(alias = "%=")]
-#[const_trait]
-pub trait RemAssign<Rhs = Self> {
+pub const trait RemAssign<Rhs = Self> {
     /// Performs the `%=` operation.
     ///
     /// # Example
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index 00196728219..0cd61b07373 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -32,8 +32,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[doc(alias = "!")]
-#[const_trait]
-pub trait Not {
+pub const trait Not {
     /// The resulting type after applying the `!` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -148,8 +147,7 @@ impl const Not for ! {
     message = "no implementation for `{Self} & {Rhs}`",
     label = "no implementation for `{Self} & {Rhs}`"
 )]
-#[const_trait]
-pub trait BitAnd<Rhs = Self> {
+pub const trait BitAnd<Rhs = Self> {
     /// The resulting type after applying the `&` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -253,8 +251,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
     message = "no implementation for `{Self} | {Rhs}`",
     label = "no implementation for `{Self} | {Rhs}`"
 )]
-#[const_trait]
-pub trait BitOr<Rhs = Self> {
+pub const trait BitOr<Rhs = Self> {
     /// The resulting type after applying the `|` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -358,8 +355,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
     message = "no implementation for `{Self} ^ {Rhs}`",
     label = "no implementation for `{Self} ^ {Rhs}`"
 )]
-#[const_trait]
-pub trait BitXor<Rhs = Self> {
+pub const trait BitXor<Rhs = Self> {
     /// The resulting type after applying the `^` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -462,8 +458,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
     message = "no implementation for `{Self} << {Rhs}`",
     label = "no implementation for `{Self} << {Rhs}`"
 )]
-#[const_trait]
-pub trait Shl<Rhs = Self> {
+pub const trait Shl<Rhs = Self> {
     /// The resulting type after applying the `<<` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -585,8 +580,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
     message = "no implementation for `{Self} >> {Rhs}`",
     label = "no implementation for `{Self} >> {Rhs}`"
 )]
-#[const_trait]
-pub trait Shr<Rhs = Self> {
+pub const trait Shr<Rhs = Self> {
     /// The resulting type after applying the `>>` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Output;
@@ -717,8 +711,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
     message = "no implementation for `{Self} &= {Rhs}`",
     label = "no implementation for `{Self} &= {Rhs}`"
 )]
-#[const_trait]
-pub trait BitAndAssign<Rhs = Self> {
+pub const trait BitAndAssign<Rhs = Self> {
     /// Performs the `&=` operation.
     ///
     /// # Examples
@@ -793,8 +786,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
     message = "no implementation for `{Self} |= {Rhs}`",
     label = "no implementation for `{Self} |= {Rhs}`"
 )]
-#[const_trait]
-pub trait BitOrAssign<Rhs = Self> {
+pub const trait BitOrAssign<Rhs = Self> {
     /// Performs the `|=` operation.
     ///
     /// # Examples
@@ -869,8 +861,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
     message = "no implementation for `{Self} ^= {Rhs}`",
     label = "no implementation for `{Self} ^= {Rhs}`"
 )]
-#[const_trait]
-pub trait BitXorAssign<Rhs = Self> {
+pub const trait BitXorAssign<Rhs = Self> {
     /// Performs the `^=` operation.
     ///
     /// # Examples
@@ -943,8 +934,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
     message = "no implementation for `{Self} <<= {Rhs}`",
     label = "no implementation for `{Self} <<= {Rhs}`"
 )]
-#[const_trait]
-pub trait ShlAssign<Rhs = Self> {
+pub const trait ShlAssign<Rhs = Self> {
     /// Performs the `<<=` operation.
     ///
     /// # Examples
@@ -1030,8 +1020,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
     message = "no implementation for `{Self} >>= {Rhs}`",
     label = "no implementation for `{Self} >>= {Rhs}`"
 )]
-#[const_trait]
-pub trait ShrAssign<Rhs = Self> {
+pub const trait ShrAssign<Rhs = Self> {
     /// Performs the `>>=` operation.
     ///
     /// # Examples
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 877b83d3a61..305861ea7b6 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -135,9 +135,8 @@ use crate::marker::PointeeSized;
 #[doc(alias = "&*")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Deref"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub trait Deref: PointeeSized {
+pub const trait Deref: PointeeSized {
     /// The resulting type after dereferencing.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "deref_target"]
@@ -267,9 +266,8 @@ impl<T: ?Sized> const Deref for &mut T {
 #[lang = "deref_mut"]
 #[doc(alias = "*")]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub trait DerefMut: [const] Deref + PointeeSized {
+pub const trait DerefMut: [const] Deref + PointeeSized {
     /// Mutably dereferences the value.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "deref_mut_method"]
diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs
index bbef7023207..7125bf54701 100644
--- a/library/core/src/ops/drop.rs
+++ b/library/core/src/ops/drop.rs
@@ -203,9 +203,8 @@
 /// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle
 #[lang = "drop"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_destruct", issue = "133214")]
-pub trait Drop {
+pub const trait Drop {
     /// Executes the destructor for this type.
     ///
     /// This method is called implicitly when the value goes out of scope,
diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs
index ad46e52a475..479368ba8f8 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -72,9 +72,8 @@ use crate::marker::Tuple;
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
-pub trait Fn<Args: Tuple>: FnMut<Args> {
+pub const trait Fn<Args: Tuple>: FnMut<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
@@ -160,9 +159,8 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
-pub trait FnMut<Args: Tuple>: FnOnce<Args> {
+pub const trait FnMut<Args: Tuple>: FnOnce<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
@@ -240,9 +238,8 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
-pub trait FnOnce<Args: Tuple> {
+pub const trait FnOnce<Args: Tuple> {
     /// The returned type after the call operator is used.
     #[lang = "fn_once_output"]
     #[stable(feature = "fn_once_output", since = "1.12.0")]
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index 1aed2fb4742..2c62a3930c2 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -55,9 +55,8 @@
 #[doc(alias = "]")]
 #[doc(alias = "[")]
 #[doc(alias = "[]")]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_index", issue = "143775")]
-pub trait Index<Idx: ?Sized> {
+pub const trait Index<Idx: ?Sized> {
     /// The returned type after indexing.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "IndexOutput"]
@@ -168,8 +167,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
 #[doc(alias = "]")]
 #[doc(alias = "[]")]
 #[rustc_const_unstable(feature = "const_index", issue = "143775")]
-#[const_trait]
-pub trait IndexMut<Idx: ?Sized>: [const] Index<Idx> {
+pub const trait IndexMut<Idx: ?Sized>: [const] Index<Idx> {
     /// Performs the mutable indexing (`container[index]`) operation.
     ///
     /// # Panics
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index c0a27775694..58a9431bd84 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -836,6 +836,7 @@ pub trait RangeBounds<T: ?Sized> {
     /// assert!(!(0.0..1.0).contains(&f32::NAN));
     /// assert!(!(0.0..f32::NAN).contains(&0.5));
     /// assert!(!(f32::NAN..1.0).contains(&0.5));
+    /// ```
     #[inline]
     #[stable(feature = "range_contains", since = "1.35.0")]
     fn contains<U>(&self, item: &U) -> bool
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 76bf438878f..e1f2ebcf4c2 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -128,9 +128,8 @@ use crate::ops::ControlFlow;
 )]
 #[doc(alias = "?")]
 #[lang = "Try"]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_try", issue = "74935")]
-pub trait Try: [const] FromResidual {
+pub const trait Try: [const] FromResidual {
     /// The type of the value produced by `?` when *not* short-circuiting.
     #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
     type Output;
@@ -306,9 +305,8 @@ pub trait Try: [const] FromResidual {
 )]
 #[rustc_diagnostic_item = "FromResidual"]
 #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_try", issue = "74935")]
-pub trait FromResidual<R = <Self as Try>::Residual> {
+pub const trait FromResidual<R = <Self as Try>::Residual> {
     /// Constructs the type from a compatible `Residual` type.
     ///
     /// This should be implemented consistently with the `branch` method such
@@ -361,9 +359,8 @@ where
 /// and in the other direction,
 /// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_try", issue = "74935")]
-pub trait Residual<O> {
+pub const trait Residual<O> {
     /// The "return" type of this meta-function.
     #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
     type TryType: Try<Output = O, Residual = Self>;
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 2a57536500a..198636c67d0 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1640,7 +1640,7 @@ impl<T> Option<T> {
     pub const fn or_else<F>(self, f: F) -> Option<T>
     where
         F: [const] FnOnce() -> Option<T> + [const] Destruct,
-        //FIXME(const_hack): this `T: ~const Destruct` is unnecessary, but even precise live drops can't tell
+        //FIXME(const_hack): this `T: [const] Destruct` is unnecessary, but even precise live drops can't tell
         // no value of type `T` gets dropped here
         T: [const] Destruct,
     {
@@ -2185,7 +2185,7 @@ const fn expect_failed(msg: &str) -> ! {
 #[rustc_const_unstable(feature = "const_clone", issue = "142757")]
 impl<T> const Clone for Option<T>
 where
-    // FIXME(const_hack): the T: ~const Destruct should be inferred from the Self: ~const Destruct in clone_from.
+    // FIXME(const_hack): the T: [const] Destruct should be inferred from the Self: [const] Destruct in clone_from.
     // See https://github.com/rust-lang/rust/issues/144207
     T: [const] Clone + [const] Destruct,
 {
diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs
index 91d015b1bc5..a13eea3fb58 100644
--- a/library/core/src/pat.rs
+++ b/library/core/src/pat.rs
@@ -18,12 +18,11 @@ macro_rules! pattern_type {
 /// used right now to simplify ast lowering of pattern type ranges.
 #[unstable(feature = "pattern_type_range_trait", issue = "123646")]
 #[rustc_const_unstable(feature = "pattern_type_range_trait", issue = "123646")]
-#[const_trait]
 #[diagnostic::on_unimplemented(
     message = "`{Self}` is not a valid base type for range patterns",
     label = "only integer types and `char` are supported"
 )]
-pub trait RangePattern {
+pub const trait RangePattern {
     /// Trait version of the inherent `MIN` assoc const.
     #[lang = "RangeMin"]
     const MIN: Self;
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 3fe4b08d459..ce6eee4f911 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -106,6 +106,7 @@ impl<T: PointeeSized> *mut T {
     ///
     /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`.
     /// println!("{:?}", unsafe { &*bad });
+    /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 68bd12aa7bf..0d801306984 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -95,9 +95,8 @@ impl<T: PartialOrd> PartialOrd for [T] {
 
 #[doc(hidden)]
 // intermediate trait for specialization of slice's PartialEq
-#[const_trait]
 #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
-trait SlicePartialEq<B> {
+const trait SlicePartialEq<B> {
     fn equal(&self, other: &[B]) -> bool;
 
     fn not_equal(&self, other: &[B]) -> bool {
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 98091e9fe83..8e1bc0bae70 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -151,7 +151,7 @@ mod private_slice_index {
     message = "the type `{T}` cannot be indexed by `{Self}`",
     label = "slice indices are of type `usize` or ranges of `usize`"
 )]
-#[const_trait]
+#[const_trait] // FIXME(const_trait_impl): Migrate to `const unsafe trait` once #146122 is fixed.
 #[rustc_const_unstable(feature = "const_index", issue = "143775")]
 pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
     /// The output type returned by methods.
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 971c8e829c6..4f228edf78e 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -825,9 +825,8 @@ unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
 /// assert!(Point::from_str("(1 2)").is_err());
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub trait FromStr: Sized {
+pub const trait FromStr: Sized {
     /// The associated error which can be returned from parsing.
     #[stable(feature = "rust1", since = "1.0.0")]
     type Err;
diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs
index f78983bc339..2f53de183f6 100644
--- a/library/core/src/unicode/unicode_data.rs
+++ b/library/core/src/unicode/unicode_data.rs
@@ -1,16 +1,15 @@
-///! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually!
-// Alphabetic      :  1727 bytes, 142759 codepoints in 757 ranges (U+000041 - U+0323B0) using skiplist
-// Case_Ignorable  :  1053 bytes,   2749 codepoints in 452 ranges (U+000027 - U+0E01F0) using skiplist
-// Cased           :   407 bytes,   4578 codepoints in 159 ranges (U+000041 - U+01F18A) using skiplist
-// Cc              :     9 bytes,     65 codepoints in   2 ranges (U+000000 - U+0000A0) using skiplist
+//! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually!
+// Alphabetic      :  1723 bytes, 142707 codepoints in 755 ranges (U+0000AA - U+0323B0) using skiplist
+// Case_Ignorable  :  1043 bytes,   2744 codepoints in 447 ranges (U+0000A8 - U+0E01F0) using skiplist
+// Cased           :   403 bytes,   4526 codepoints in 157 ranges (U+0000AA - U+01F18A) using skiplist
 // Grapheme_Extend :   887 bytes,   2193 codepoints in 375 ranges (U+000300 - U+0E01F0) using skiplist
-// Lowercase       :   935 bytes,   2569 codepoints in 675 ranges (U+000061 - U+01E944) using bitset
-// N               :   457 bytes,   1911 codepoints in 144 ranges (U+000030 - U+01FBFA) using skiplist
-// Uppercase       :   799 bytes,   1978 codepoints in 656 ranges (U+000041 - U+01F18A) using bitset
-// White_Space     :   256 bytes,     25 codepoints in  10 ranges (U+000009 - U+003001) using cascading
+// Lowercase       :   933 bytes,   2543 codepoints in 674 ranges (U+0000AA - U+01E944) using bitset
+// N               :   455 bytes,   1901 codepoints in 143 ranges (U+0000B2 - U+01FBFA) using skiplist
+// Uppercase       :   797 bytes,   1952 codepoints in 655 ranges (U+0000C0 - U+01F18A) using bitset
+// White_Space     :   256 bytes,     19 codepoints in   8 ranges (U+000085 - U+003001) using cascading
 // to_lower        : 11484 bytes
 // to_upper        : 13432 bytes
-// Total           : 31446 bytes
+// Total           : 31413 bytes
 
 #[inline(always)]
 const fn bitset_search<
@@ -148,93 +147,100 @@ pub mod alphabetic {
     use super::ShortOffsetRunHeader;
 
     static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 53] = [
-        ShortOffsetRunHeader::new(0, 706), ShortOffsetRunHeader::new(16, 4681),
-        ShortOffsetRunHeader::new(418, 5741), ShortOffsetRunHeader::new(456, 7958),
-        ShortOffsetRunHeader::new(556, 9398), ShortOffsetRunHeader::new(627, 11264),
-        ShortOffsetRunHeader::new(629, 12293), ShortOffsetRunHeader::new(667, 13312),
-        ShortOffsetRunHeader::new(691, 19904), ShortOffsetRunHeader::new(692, 42125),
-        ShortOffsetRunHeader::new(694, 42509), ShortOffsetRunHeader::new(698, 55204),
-        ShortOffsetRunHeader::new(788, 63744), ShortOffsetRunHeader::new(793, 64110),
-        ShortOffsetRunHeader::new(794, 64830), ShortOffsetRunHeader::new(816, 66176),
-        ShortOffsetRunHeader::new(857, 67383), ShortOffsetRunHeader::new(904, 73440),
-        ShortOffsetRunHeader::new(1221, 74650), ShortOffsetRunHeader::new(1232, 77712),
-        ShortOffsetRunHeader::new(1237, 78896), ShortOffsetRunHeader::new(1240, 82939),
-        ShortOffsetRunHeader::new(1244, 83527), ShortOffsetRunHeader::new(1246, 90368),
-        ShortOffsetRunHeader::new(1247, 92160), ShortOffsetRunHeader::new(1249, 92729),
-        ShortOffsetRunHeader::new(1250, 93504), ShortOffsetRunHeader::new(1265, 100344),
-        ShortOffsetRunHeader::new(1282, 101590), ShortOffsetRunHeader::new(1284, 110576),
-        ShortOffsetRunHeader::new(1287, 110883), ShortOffsetRunHeader::new(1294, 111356),
-        ShortOffsetRunHeader::new(1304, 113664), ShortOffsetRunHeader::new(1305, 119808),
-        ShortOffsetRunHeader::new(1315, 120486), ShortOffsetRunHeader::new(1352, 122624),
-        ShortOffsetRunHeader::new(1375, 123536), ShortOffsetRunHeader::new(1399, 124112),
-        ShortOffsetRunHeader::new(1403, 124896), ShortOffsetRunHeader::new(1409, 126464),
-        ShortOffsetRunHeader::new(1425, 127280), ShortOffsetRunHeader::new(1491, 131072),
-        ShortOffsetRunHeader::new(1497, 173792), ShortOffsetRunHeader::new(1498, 177978),
-        ShortOffsetRunHeader::new(1500, 183970), ShortOffsetRunHeader::new(1504, 191457),
-        ShortOffsetRunHeader::new(1506, 192094), ShortOffsetRunHeader::new(1508, 194560),
-        ShortOffsetRunHeader::new(1509, 195102), ShortOffsetRunHeader::new(1510, 196608),
-        ShortOffsetRunHeader::new(1511, 201547), ShortOffsetRunHeader::new(1512, 205744),
-        ShortOffsetRunHeader::new(1514, 1319856),
+        ShortOffsetRunHeader::new(0, 706), ShortOffsetRunHeader::new(12, 4681),
+        ShortOffsetRunHeader::new(414, 5741), ShortOffsetRunHeader::new(452, 7958),
+        ShortOffsetRunHeader::new(552, 9398), ShortOffsetRunHeader::new(623, 11264),
+        ShortOffsetRunHeader::new(625, 12293), ShortOffsetRunHeader::new(663, 13312),
+        ShortOffsetRunHeader::new(687, 19904), ShortOffsetRunHeader::new(688, 42125),
+        ShortOffsetRunHeader::new(690, 42509), ShortOffsetRunHeader::new(694, 55204),
+        ShortOffsetRunHeader::new(784, 63744), ShortOffsetRunHeader::new(789, 64110),
+        ShortOffsetRunHeader::new(790, 64830), ShortOffsetRunHeader::new(812, 66176),
+        ShortOffsetRunHeader::new(853, 67383), ShortOffsetRunHeader::new(900, 73440),
+        ShortOffsetRunHeader::new(1217, 74650), ShortOffsetRunHeader::new(1228, 77712),
+        ShortOffsetRunHeader::new(1233, 78896), ShortOffsetRunHeader::new(1236, 82939),
+        ShortOffsetRunHeader::new(1240, 83527), ShortOffsetRunHeader::new(1242, 90368),
+        ShortOffsetRunHeader::new(1243, 92160), ShortOffsetRunHeader::new(1245, 92729),
+        ShortOffsetRunHeader::new(1246, 93504), ShortOffsetRunHeader::new(1261, 100344),
+        ShortOffsetRunHeader::new(1278, 101590), ShortOffsetRunHeader::new(1280, 110576),
+        ShortOffsetRunHeader::new(1283, 110883), ShortOffsetRunHeader::new(1290, 111356),
+        ShortOffsetRunHeader::new(1300, 113664), ShortOffsetRunHeader::new(1301, 119808),
+        ShortOffsetRunHeader::new(1311, 120486), ShortOffsetRunHeader::new(1348, 122624),
+        ShortOffsetRunHeader::new(1371, 123536), ShortOffsetRunHeader::new(1395, 124112),
+        ShortOffsetRunHeader::new(1399, 124896), ShortOffsetRunHeader::new(1405, 126464),
+        ShortOffsetRunHeader::new(1421, 127280), ShortOffsetRunHeader::new(1487, 131072),
+        ShortOffsetRunHeader::new(1493, 173792), ShortOffsetRunHeader::new(1494, 177978),
+        ShortOffsetRunHeader::new(1496, 183970), ShortOffsetRunHeader::new(1500, 191457),
+        ShortOffsetRunHeader::new(1502, 192094), ShortOffsetRunHeader::new(1504, 194560),
+        ShortOffsetRunHeader::new(1505, 195102), ShortOffsetRunHeader::new(1506, 196608),
+        ShortOffsetRunHeader::new(1507, 201547), ShortOffsetRunHeader::new(1508, 205744),
+        ShortOffsetRunHeader::new(1510, 1319856),
     ];
-    static OFFSETS: [u8; 1515] = [
-        65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 29,
-        18, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41,
-        39, 14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3,
-        10, 3, 2, 1, 16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 5, 24, 1, 6,
-        8, 1, 8, 42, 10, 12, 3, 7, 6, 76, 1, 16, 1, 3, 4, 15, 13, 19, 1, 8, 2, 2, 2, 22, 1, 7, 1, 1,
-        3, 4, 3, 8, 2, 2, 2, 2, 1, 1, 8, 1, 4, 2, 1, 5, 12, 2, 10, 1, 4, 3, 1, 6, 4, 2, 2, 22, 1, 7,
-        1, 2, 1, 2, 1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7,
-        1, 2, 1, 5, 3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5,
-        3, 8, 2, 2, 2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2,
-        3, 3, 3, 12, 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 13, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8,
-        2, 1, 3, 2, 1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1,
-        4, 13, 3, 12, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3,
-        24, 1, 9, 1, 1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24,
-        1, 1, 1, 19, 1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 19, 4, 16, 1, 36, 67,
-        55, 1, 1, 2, 5, 16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2,
-        41, 1, 4, 2, 33, 1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3,
-        0, 2, 17, 1, 26, 5, 75, 3, 11, 7, 20, 11, 21, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14,
-        1, 4, 1, 67, 89, 7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4,
-        63, 2, 20, 50, 1, 23, 2, 11, 3, 49, 52, 1, 15, 1, 8, 51, 42, 2, 4, 10, 44, 1, 11, 14, 55,
-        22, 3, 10, 36, 2, 11, 5, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 19, 34, 11, 0, 2, 6, 2,
-        38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13,
-        5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4,
-        1, 11, 2, 4, 5, 5, 4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1,
-        16, 23, 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2,
-        5, 4, 86, 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16,
-        10, 2, 20, 47, 5, 8, 3, 113, 39, 9, 2, 103, 2, 67, 2, 2, 1, 1, 1, 8, 21, 20, 1, 33, 24, 52,
-        12, 68, 1, 1, 44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5,
-        1, 55, 9, 14, 18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7,
-        1, 43, 1, 14, 6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5,
-        1, 1, 1, 2, 1, 2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11,
-        89, 3, 6, 2, 6, 2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0,
-        29, 3, 49, 47, 32, 13, 30, 5, 43, 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40,
-        8, 52, 12, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 3, 52, 12, 0, 9, 22, 10, 8, 24,
-        6, 1, 42, 1, 9, 69, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22,
-        10, 26, 70, 56, 6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54,
-        10, 22, 10, 19, 13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 34, 28, 3, 1, 5, 23, 250, 42, 1, 2,
-        3, 2, 16, 3, 55, 1, 3, 29, 10, 1, 8, 22, 42, 18, 46, 21, 27, 23, 9, 70, 43, 5, 10, 57, 9, 1,
-        13, 25, 23, 51, 17, 4, 8, 35, 3, 1, 9, 64, 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6,
-        4, 62, 7, 1, 1, 1, 4, 1, 15, 1, 10, 7, 57, 23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8,
-        2, 2, 2, 2, 3, 1, 6, 1, 5, 7, 28, 10, 1, 1, 2, 1, 1, 38, 1, 10, 1, 1, 2, 1, 1, 4, 1, 2, 3,
-        1, 1, 1, 44, 66, 1, 3, 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1,
-        3, 1, 59, 54, 2, 1, 71, 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30,
-        1, 2, 2, 2, 2, 4, 93, 8, 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 199,
-        33, 31, 9, 1, 45, 1, 7, 1, 1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1,
-        1, 2, 2, 24, 6, 1, 2, 1, 37, 1, 2, 1, 4, 1, 1, 0, 23, 9, 17, 1, 41, 3, 3, 111, 1, 79, 0,
-        102, 111, 17, 196, 0, 97, 15, 0, 17, 6, 25, 0, 5, 0, 0, 47, 0, 0, 7, 31, 17, 79, 17, 30, 18,
-        48, 16, 4, 31, 21, 5, 19, 0, 45, 211, 64, 128, 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 2, 14, 0,
-        8, 0, 41, 10, 0, 4, 1, 7, 1, 2, 1, 0, 15, 1, 29, 3, 2, 1, 14, 4, 8, 0, 0, 107, 5, 13, 3, 9,
-        7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1,
-        7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1,
-        25, 1, 31, 1, 25, 1, 8, 0, 31, 6, 6, 213, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 112, 45,
-        10, 7, 16, 1, 0, 30, 18, 44, 0, 28, 228, 30, 2, 1, 0, 7, 1, 4, 1, 2, 1, 15, 1, 197, 59, 68,
-        3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1,
-        1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1,
-        10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32, 0, 6, 222, 2, 0, 14, 0, 15, 0,
-        0, 0, 0, 0, 5, 0, 0,
+    static OFFSETS: [u8; 1511] = [
+        170, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 29, 18, 1, 2, 2,
+        4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39, 14, 1, 1,
+        1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10, 3, 2, 1,
+        16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 5, 24, 1, 6, 8, 1, 8, 42,
+        10, 12, 3, 7, 6, 76, 1, 16, 1, 3, 4, 15, 13, 19, 1, 8, 2, 2, 2, 22, 1, 7, 1, 1, 3, 4, 3, 8,
+        2, 2, 2, 2, 1, 1, 8, 1, 4, 2, 1, 5, 12, 2, 10, 1, 4, 3, 1, 6, 4, 2, 2, 22, 1, 7, 1, 2, 1, 2,
+        1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7, 1, 2, 1, 5,
+        3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2,
+        2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2, 3, 3, 3, 12,
+        4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 13, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2, 1, 3, 2,
+        1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1, 4, 13, 3,
+        12, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, 24, 1, 9, 1,
+        1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, 1, 1, 1, 19,
+        1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 19, 4, 16, 1, 36, 67, 55, 1, 1, 2, 5,
+        16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2, 41, 1, 4, 2, 33,
+        1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3, 0, 2, 17, 1, 26,
+        5, 75, 3, 11, 7, 20, 11, 21, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14, 1, 4, 1, 67, 89,
+        7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4, 63, 2, 20, 50, 1,
+        23, 2, 11, 3, 49, 52, 1, 15, 1, 8, 51, 42, 2, 4, 10, 44, 1, 11, 14, 55, 22, 3, 10, 36, 2,
+        11, 5, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 19, 34, 11, 0, 2, 6, 2, 38, 2, 6, 2, 8, 1,
+        1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, 7, 116, 1,
+        13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 11, 2, 4, 5, 5,
+        4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, 16, 23, 9, 7, 1,
+        7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, 5, 4, 86, 6, 3,
+        1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16, 10, 2, 20, 47,
+        5, 8, 3, 113, 39, 9, 2, 103, 2, 67, 2, 2, 1, 1, 1, 8, 21, 20, 1, 33, 24, 52, 12, 68, 1, 1,
+        44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, 1, 55, 9, 14,
+        18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, 1, 43, 1, 14,
+        6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, 1, 1, 1, 2, 1,
+        2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, 89, 3, 6, 2, 6,
+        2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, 29, 3, 49, 47, 32,
+        13, 30, 5, 43, 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40, 8, 52, 12, 11, 1,
+        15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 3, 52, 12, 0, 9, 22, 10, 8, 24, 6, 1, 42, 1, 9,
+        69, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22, 10, 26, 70, 56,
+        6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54, 10, 22, 10, 19,
+        13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 34, 28, 3, 1, 5, 23, 250, 42, 1, 2, 3, 2, 16, 3,
+        55, 1, 3, 29, 10, 1, 8, 22, 42, 18, 46, 21, 27, 23, 9, 70, 43, 5, 10, 57, 9, 1, 13, 25, 23,
+        51, 17, 4, 8, 35, 3, 1, 9, 64, 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 4, 62, 7, 1,
+        1, 1, 4, 1, 15, 1, 10, 7, 57, 23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2,
+        3, 1, 6, 1, 5, 7, 28, 10, 1, 1, 2, 1, 1, 38, 1, 10, 1, 1, 2, 1, 1, 4, 1, 2, 3, 1, 1, 1, 44,
+        66, 1, 3, 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, 3, 1, 59, 54,
+        2, 1, 71, 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, 1, 2, 2, 2, 2,
+        4, 93, 8, 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 199, 33, 31, 9, 1,
+        45, 1, 7, 1, 1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, 1, 2, 2, 24,
+        6, 1, 2, 1, 37, 1, 2, 1, 4, 1, 1, 0, 23, 9, 17, 1, 41, 3, 3, 111, 1, 79, 0, 102, 111, 17,
+        196, 0, 97, 15, 0, 17, 6, 25, 0, 5, 0, 0, 47, 0, 0, 7, 31, 17, 79, 17, 30, 18, 48, 16, 4,
+        31, 21, 5, 19, 0, 45, 211, 64, 128, 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 2, 14, 0, 8, 0, 41,
+        10, 0, 4, 1, 7, 1, 2, 1, 0, 15, 1, 29, 3, 2, 1, 14, 4, 8, 0, 0, 107, 5, 13, 3, 9, 7, 10, 4,
+        1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28,
+        1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31,
+        1, 25, 1, 8, 0, 31, 6, 6, 213, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 112, 45, 10, 7, 16,
+        1, 0, 30, 18, 44, 0, 28, 228, 30, 2, 1, 0, 7, 1, 4, 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1,
+        0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2,
+        1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17,
+        5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32, 0, 6, 222, 2, 0, 14, 0, 15, 0, 0, 0, 0, 0,
+        5, 0, 0,
     ];
+    #[inline]
     pub fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
+        (c as u32) >= 0xaa && lookup_slow(c)
+    }
+
+    #[inline(never)]
+    fn lookup_slow(c: char) -> bool {
         const {
             assert!(SHORT_OFFSET_RUNS.last().unwrap().0 > char::MAX as u32);
             let mut i = 0;
@@ -254,62 +260,69 @@ pub mod case_ignorable {
     use super::ShortOffsetRunHeader;
 
     static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 37] = [
-        ShortOffsetRunHeader::new(0, 688), ShortOffsetRunHeader::new(21, 4957),
-        ShortOffsetRunHeader::new(273, 5906), ShortOffsetRunHeader::new(275, 8125),
-        ShortOffsetRunHeader::new(385, 11388), ShortOffsetRunHeader::new(419, 12293),
-        ShortOffsetRunHeader::new(431, 40981), ShortOffsetRunHeader::new(443, 42232),
-        ShortOffsetRunHeader::new(445, 42508), ShortOffsetRunHeader::new(447, 64286),
-        ShortOffsetRunHeader::new(543, 65024), ShortOffsetRunHeader::new(547, 66045),
-        ShortOffsetRunHeader::new(577, 67456), ShortOffsetRunHeader::new(583, 68097),
-        ShortOffsetRunHeader::new(589, 68900), ShortOffsetRunHeader::new(601, 69291),
-        ShortOffsetRunHeader::new(609, 71727), ShortOffsetRunHeader::new(733, 71995),
-        ShortOffsetRunHeader::new(737, 72752), ShortOffsetRunHeader::new(765, 73459),
-        ShortOffsetRunHeader::new(795, 78896), ShortOffsetRunHeader::new(807, 90398),
-        ShortOffsetRunHeader::new(811, 92912), ShortOffsetRunHeader::new(815, 93504),
-        ShortOffsetRunHeader::new(821, 94031), ShortOffsetRunHeader::new(825, 110576),
-        ShortOffsetRunHeader::new(833, 113821), ShortOffsetRunHeader::new(839, 118528),
-        ShortOffsetRunHeader::new(843, 119143), ShortOffsetRunHeader::new(847, 121344),
-        ShortOffsetRunHeader::new(857, 122880), ShortOffsetRunHeader::new(869, 123566),
-        ShortOffsetRunHeader::new(885, 124139), ShortOffsetRunHeader::new(889, 125136),
-        ShortOffsetRunHeader::new(893, 127995), ShortOffsetRunHeader::new(897, 917505),
-        ShortOffsetRunHeader::new(899, 2032112),
+        ShortOffsetRunHeader::new(0, 688), ShortOffsetRunHeader::new(11, 4957),
+        ShortOffsetRunHeader::new(263, 5906), ShortOffsetRunHeader::new(265, 8125),
+        ShortOffsetRunHeader::new(375, 11388), ShortOffsetRunHeader::new(409, 12293),
+        ShortOffsetRunHeader::new(421, 40981), ShortOffsetRunHeader::new(433, 42232),
+        ShortOffsetRunHeader::new(435, 42508), ShortOffsetRunHeader::new(437, 64286),
+        ShortOffsetRunHeader::new(533, 65024), ShortOffsetRunHeader::new(537, 66045),
+        ShortOffsetRunHeader::new(567, 67456), ShortOffsetRunHeader::new(573, 68097),
+        ShortOffsetRunHeader::new(579, 68900), ShortOffsetRunHeader::new(591, 69291),
+        ShortOffsetRunHeader::new(599, 71727), ShortOffsetRunHeader::new(723, 71995),
+        ShortOffsetRunHeader::new(727, 72752), ShortOffsetRunHeader::new(755, 73459),
+        ShortOffsetRunHeader::new(785, 78896), ShortOffsetRunHeader::new(797, 90398),
+        ShortOffsetRunHeader::new(801, 92912), ShortOffsetRunHeader::new(805, 93504),
+        ShortOffsetRunHeader::new(811, 94031), ShortOffsetRunHeader::new(815, 110576),
+        ShortOffsetRunHeader::new(823, 113821), ShortOffsetRunHeader::new(829, 118528),
+        ShortOffsetRunHeader::new(833, 119143), ShortOffsetRunHeader::new(837, 121344),
+        ShortOffsetRunHeader::new(847, 122880), ShortOffsetRunHeader::new(859, 123566),
+        ShortOffsetRunHeader::new(875, 124139), ShortOffsetRunHeader::new(879, 125136),
+        ShortOffsetRunHeader::new(883, 127995), ShortOffsetRunHeader::new(887, 917505),
+        ShortOffsetRunHeader::new(889, 2032112),
     ];
-    static OFFSETS: [u8; 905] = [
-        39, 1, 6, 1, 11, 1, 35, 1, 1, 1, 71, 1, 4, 1, 1, 1, 4, 1, 2, 2, 0, 192, 4, 2, 4, 1, 9, 2,
-        1, 1, 251, 7, 207, 1, 5, 1, 49, 45, 1, 1, 1, 2, 1, 2, 1, 1, 44, 1, 11, 6, 10, 11, 1, 1, 35,
-        1, 10, 21, 16, 1, 101, 8, 1, 10, 1, 4, 33, 1, 1, 1, 30, 27, 91, 11, 58, 11, 4, 1, 2, 1, 24,
-        24, 43, 3, 44, 1, 7, 2, 5, 9, 41, 58, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 13, 1, 15, 1,
-        58, 1, 4, 4, 8, 1, 20, 2, 26, 1, 2, 2, 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2,
-        57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6, 1, 1, 58, 1, 2, 1, 1, 4, 8, 1, 7, 2, 11, 2, 30, 1,
-        61, 1, 12, 1, 50, 1, 3, 1, 55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 6, 1,
-        5, 2, 20, 2, 28, 2, 57, 2, 4, 4, 8, 1, 20, 2, 29, 1, 72, 1, 7, 3, 1, 1, 90, 1, 2, 7, 11, 9,
-        98, 1, 2, 9, 9, 1, 1, 7, 73, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1,
-        102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 94, 1, 0, 3, 0, 3,
-        29, 2, 30, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 3, 1, 5, 1, 45, 5, 51, 1, 65, 2, 34, 1, 118,
-        3, 4, 2, 9, 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 39, 1, 8, 31,
-        49, 4, 48, 1, 1, 5, 1, 1, 5, 1, 40, 9, 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3,
-        58, 8, 2, 2, 64, 6, 82, 3, 1, 13, 1, 7, 4, 1, 6, 1, 3, 2, 50, 63, 13, 1, 34, 101, 0, 1, 1,
-        3, 11, 3, 13, 3, 13, 3, 13, 2, 12, 5, 8, 2, 10, 1, 2, 1, 2, 5, 49, 5, 1, 10, 1, 1, 13, 1,
-        16, 13, 51, 33, 0, 2, 113, 3, 125, 1, 15, 1, 96, 32, 47, 1, 0, 1, 36, 4, 3, 5, 5, 1, 93, 6,
-        93, 3, 0, 1, 0, 6, 0, 1, 98, 4, 1, 10, 1, 1, 28, 4, 80, 2, 14, 34, 78, 1, 23, 3, 103, 3, 3,
-        2, 8, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, 46, 3, 48, 1, 2, 4,
-        2, 2, 17, 1, 21, 2, 66, 6, 2, 2, 2, 2, 12, 1, 8, 1, 35, 1, 11, 1, 51, 1, 1, 3, 2, 2, 5, 2,
-        1, 1, 27, 1, 14, 2, 5, 2, 1, 1, 100, 5, 9, 3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 17, 0, 16, 3,
-        1, 12, 16, 34, 1, 2, 1, 169, 1, 7, 1, 6, 1, 11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3,
-        0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 38, 1,
-        26, 5, 1, 1, 0, 2, 79, 4, 70, 11, 49, 4, 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2,
-        1, 4, 1, 10, 1, 50, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6,
-        1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 3, 1, 37, 7, 3, 5, 70, 6, 13, 1, 1, 1, 1, 1, 14, 2, 85,
-        8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, 2, 1, 2, 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2,
-        106, 1, 1, 1, 2, 6, 1, 1, 101, 1, 1, 1, 2, 4, 1, 5, 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2,
-        2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2,
-        7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 1,
-        1, 1, 23, 1, 0, 17, 6, 15, 0, 12, 3, 3, 0, 5, 59, 7, 9, 4, 0, 3, 40, 2, 0, 1, 63, 17, 64, 2,
-        1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, 0, 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, 55,
-        4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 160, 14, 0,
-        1, 61, 4, 0, 5, 254, 2, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, 128, 240, 0,
+    static OFFSETS: [u8; 895] = [
+        168, 1, 4, 1, 1, 1, 4, 1, 2, 2, 0, 192, 4, 2, 4, 1, 9, 2, 1, 1, 251, 7, 207, 1, 5, 1, 49,
+        45, 1, 1, 1, 2, 1, 2, 1, 1, 44, 1, 11, 6, 10, 11, 1, 1, 35, 1, 10, 21, 16, 1, 101, 8, 1, 10,
+        1, 4, 33, 1, 1, 1, 30, 27, 91, 11, 58, 11, 4, 1, 2, 1, 24, 24, 43, 3, 44, 1, 7, 2, 5, 9, 41,
+        58, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 13, 1, 15, 1, 58, 1, 4, 4, 8, 1, 20, 2, 26, 1, 2,
+        2, 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2, 57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6,
+        1, 1, 58, 1, 2, 1, 1, 4, 8, 1, 7, 2, 11, 2, 30, 1, 61, 1, 12, 1, 50, 1, 3, 1, 55, 1, 1, 3,
+        5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 6, 1, 5, 2, 20, 2, 28, 2, 57, 2, 4, 4, 8, 1,
+        20, 2, 29, 1, 72, 1, 7, 3, 1, 1, 90, 1, 2, 7, 11, 9, 98, 1, 2, 9, 9, 1, 1, 7, 73, 2, 27, 1,
+        1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, 102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3,
+        16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 94, 1, 0, 3, 0, 3, 29, 2, 30, 2, 30, 2, 64, 2, 1, 7, 8, 1,
+        2, 11, 3, 1, 5, 1, 45, 5, 51, 1, 65, 2, 34, 1, 118, 3, 4, 2, 9, 1, 6, 3, 219, 2, 2, 1, 58,
+        1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 39, 1, 8, 31, 49, 4, 48, 1, 1, 5, 1, 1, 5, 1, 40, 9,
+        12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, 58, 8, 2, 2, 64, 6, 82, 3, 1, 13, 1, 7,
+        4, 1, 6, 1, 3, 2, 50, 63, 13, 1, 34, 101, 0, 1, 1, 3, 11, 3, 13, 3, 13, 3, 13, 2, 12, 5, 8,
+        2, 10, 1, 2, 1, 2, 5, 49, 5, 1, 10, 1, 1, 13, 1, 16, 13, 51, 33, 0, 2, 113, 3, 125, 1, 15,
+        1, 96, 32, 47, 1, 0, 1, 36, 4, 3, 5, 5, 1, 93, 6, 93, 3, 0, 1, 0, 6, 0, 1, 98, 4, 1, 10, 1,
+        1, 28, 4, 80, 2, 14, 34, 78, 1, 23, 3, 103, 3, 3, 2, 8, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2,
+        26, 18, 13, 1, 38, 8, 25, 11, 46, 3, 48, 1, 2, 4, 2, 2, 17, 1, 21, 2, 66, 6, 2, 2, 2, 2, 12,
+        1, 8, 1, 35, 1, 11, 1, 51, 1, 1, 3, 2, 2, 5, 2, 1, 1, 27, 1, 14, 2, 5, 2, 1, 1, 100, 5, 9,
+        3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 17, 0, 16, 3, 1, 12, 16, 34, 1, 2, 1, 169, 1, 7, 1, 6, 1,
+        11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3, 0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, 0,
+        3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 38, 1, 26, 5, 1, 1, 0, 2, 79, 4, 70, 11, 49, 4,
+        123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, 1, 4, 1, 10, 1, 50, 3, 36, 5, 1, 8, 62,
+        1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 3,
+        1, 37, 7, 3, 5, 70, 6, 13, 1, 1, 1, 1, 1, 14, 2, 85, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4,
+        2, 1, 2, 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 1, 1,
+        1, 2, 4, 1, 5, 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1,
+        9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1,
+        7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 1, 1, 1, 23, 1, 0, 17, 6, 15, 0, 12, 3,
+        3, 0, 5, 59, 7, 9, 4, 0, 3, 40, 2, 0, 1, 63, 17, 64, 2, 1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4,
+        0, 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0,
+        7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 160, 14, 0, 1, 61, 4, 0, 5, 254, 2, 0, 7, 109, 8,
+        0, 5, 0, 1, 30, 96, 128, 240, 0,
     ];
+    #[inline]
     pub fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
+        (c as u32) >= 0xa8 && lookup_slow(c)
+    }
+
+    #[inline(never)]
+    fn lookup_slow(c: char) -> bool {
         const {
             assert!(SHORT_OFFSET_RUNS.last().unwrap().0 > char::MAX as u32);
             let mut i = 0;
@@ -329,33 +342,40 @@ pub mod cased {
     use super::ShortOffsetRunHeader;
 
     static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 22] = [
-        ShortOffsetRunHeader::new(0, 4256), ShortOffsetRunHeader::new(55, 5024),
-        ShortOffsetRunHeader::new(65, 7296), ShortOffsetRunHeader::new(69, 7958),
-        ShortOffsetRunHeader::new(78, 9398), ShortOffsetRunHeader::new(153, 11264),
-        ShortOffsetRunHeader::new(155, 42560), ShortOffsetRunHeader::new(167, 43824),
-        ShortOffsetRunHeader::new(187, 64256), ShortOffsetRunHeader::new(193, 65313),
-        ShortOffsetRunHeader::new(197, 66560), ShortOffsetRunHeader::new(201, 67456),
-        ShortOffsetRunHeader::new(223, 68736), ShortOffsetRunHeader::new(231, 71840),
-        ShortOffsetRunHeader::new(239, 93760), ShortOffsetRunHeader::new(241, 119808),
-        ShortOffsetRunHeader::new(243, 120486), ShortOffsetRunHeader::new(280, 122624),
-        ShortOffsetRunHeader::new(303, 122928), ShortOffsetRunHeader::new(309, 125184),
-        ShortOffsetRunHeader::new(311, 127280), ShortOffsetRunHeader::new(313, 1241482),
+        ShortOffsetRunHeader::new(0, 4256), ShortOffsetRunHeader::new(51, 5024),
+        ShortOffsetRunHeader::new(61, 7296), ShortOffsetRunHeader::new(65, 7958),
+        ShortOffsetRunHeader::new(74, 9398), ShortOffsetRunHeader::new(149, 11264),
+        ShortOffsetRunHeader::new(151, 42560), ShortOffsetRunHeader::new(163, 43824),
+        ShortOffsetRunHeader::new(183, 64256), ShortOffsetRunHeader::new(189, 65313),
+        ShortOffsetRunHeader::new(193, 66560), ShortOffsetRunHeader::new(197, 67456),
+        ShortOffsetRunHeader::new(219, 68736), ShortOffsetRunHeader::new(227, 71840),
+        ShortOffsetRunHeader::new(235, 93760), ShortOffsetRunHeader::new(237, 119808),
+        ShortOffsetRunHeader::new(239, 120486), ShortOffsetRunHeader::new(276, 122624),
+        ShortOffsetRunHeader::new(299, 122928), ShortOffsetRunHeader::new(305, 125184),
+        ShortOffsetRunHeader::new(307, 127280), ShortOffsetRunHeader::new(309, 1241482),
     ];
-    static OFFSETS: [u8; 319] = [
-        65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 195, 1, 4, 4, 208, 1, 36, 7, 2, 30, 5,
-        96, 1, 42, 4, 2, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 9,
-        41, 0, 38, 1, 1, 5, 1, 2, 43, 1, 4, 0, 86, 2, 6, 0, 11, 5, 43, 2, 3, 64, 192, 64, 0, 2, 6,
-        2, 38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4,
-        13, 5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1,
-        4, 1, 6, 4, 1, 2, 4, 5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5,
-        1, 0, 46, 18, 30, 132, 102, 3, 4, 1, 62, 2, 2, 1, 1, 1, 8, 21, 5, 1, 3, 0, 43, 1, 14, 6, 80,
-        0, 7, 12, 5, 0, 26, 6, 26, 0, 80, 96, 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15,
-        1, 7, 1, 2, 0, 1, 2, 3, 1, 42, 1, 9, 0, 51, 13, 51, 93, 22, 10, 22, 0, 64, 0, 64, 0, 85, 1,
-        71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5,
-        1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1,
-        8, 0, 10, 1, 20, 6, 6, 0, 62, 0, 68, 0, 26, 6, 26, 6, 26, 0,
+    static OFFSETS: [u8; 315] = [
+        170, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 195, 1, 4, 4, 208, 1, 36, 7, 2, 30, 5, 96, 1, 42, 4,
+        2, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 9, 41, 0, 38, 1, 1,
+        5, 1, 2, 43, 1, 4, 0, 86, 2, 6, 0, 11, 5, 43, 2, 3, 64, 192, 64, 0, 2, 6, 2, 38, 2, 6, 2, 8,
+        1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, 7, 116,
+        1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 6, 4, 1, 2, 4,
+        5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 0, 46, 18, 30, 132,
+        102, 3, 4, 1, 62, 2, 2, 1, 1, 1, 8, 21, 5, 1, 3, 0, 43, 1, 14, 6, 80, 0, 7, 12, 5, 0, 26, 6,
+        26, 0, 80, 96, 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 0, 1, 2, 3,
+        1, 42, 1, 9, 0, 51, 13, 51, 93, 22, 10, 22, 0, 64, 0, 64, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2,
+        4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25,
+        1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 10, 1, 20, 6, 6, 0,
+        62, 0, 68, 0, 26, 6, 26, 6, 26, 0,
     ];
+    #[inline]
     pub fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
+        (c as u32) >= 0xaa && lookup_slow(c)
+    }
+
+    #[inline(never)]
+    fn lookup_slow(c: char) -> bool {
         const {
             assert!(SHORT_OFFSET_RUNS.last().unwrap().0 > char::MAX as u32);
             let mut i = 0;
@@ -424,6 +444,7 @@ pub mod grapheme_extend {
     ];
     #[inline]
     pub fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
         (c as u32) >= 0x300 && lookup_slow(c)
     }
 
@@ -446,7 +467,7 @@ pub mod grapheme_extend {
 #[rustfmt::skip]
 pub mod lowercase {
     static BITSET_CHUNKS_MAP: [u8; 123] = [
-        14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        12, 17, 0, 0, 9, 0, 0, 13, 14, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0,
@@ -458,37 +479,37 @@ pub mod lowercase {
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 56, 0],
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0],
-        [0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0],
+        [0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 43, 0, 52, 48, 50, 33],
-        [0, 0, 0, 0, 10, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        [0, 0, 0, 0, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 3, 0, 16, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27],
         [0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        [0, 0, 34, 17, 23, 53, 54, 49, 47, 7, 35, 42, 0, 28, 12, 31],
         [0, 0, 46, 0, 56, 56, 56, 0, 22, 22, 69, 22, 36, 25, 24, 37],
         [0, 5, 70, 0, 29, 15, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        [0, 66, 34, 17, 23, 53, 54, 49, 47, 8, 35, 42, 0, 28, 13, 31],
-        [11, 60, 0, 6, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 32, 0],
+        [10, 60, 0, 6, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 32, 0],
         [16, 26, 22, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        [16, 51, 2, 21, 68, 9, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        [16, 51, 2, 21, 68, 8, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [16, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        [65, 41, 55, 12, 77, 63, 18, 1, 7, 64, 76, 20, 73, 74, 4, 45],
+        [65, 41, 55, 11, 66, 63, 18, 13, 1, 64, 76, 20, 73, 74, 4, 45],
     ];
     static BITSET_CANONICAL: [u64; 56] = [
         0b0000000000000000000000000000000000000000000000000000000000000000,
-        0b1111111111111111110000000000000000000000000011111111111111111111,
+        0b0000111111111111111111111111110000000000000000000000000011111111,
         0b1010101010101010101010101010101010101010101010101010100000000010,
         0b0000000000000111111111111111111111111111111111111111111111111111,
         0b1111111111111111111111000000000000000000000000001111110111111111,
         0b1000000000000010000000000000000000000000000000000000000000000000,
         0b0000111111111111111111111111111111111111000000000000000000000000,
-        0b0000111111111111111111111111110000000000000000000000000011111111,
         0b1111111111111111111111111111111111111111111111111010101010000101,
         0b1111111111111111111111111111111100000000000000000000000000000000,
         0b1111111111111111111111111111110000000000000000000000000000000000,
         0b1111111111111111111111110000000000000000000000000000000000000000,
         0b1111111111111111111111000000000000000000000000001111111111101111,
         0b1111111111111111111100000000000000000000000000010000000000000000,
+        0b1111111111111111110000000000000000000000000011111111111111111111,
         0b1111111111111111000000111111111111110111111111111111111111111111,
         0b1111111111111111000000000000000000000000000000000100001111000000,
         0b1111111111111111000000000000000000000000000000000000000000000000,
@@ -532,13 +553,15 @@ pub mod lowercase {
         0b1110011001010001001011010010101001001110001001000011000100101001,
         0b1110101111000000000000000000000000001111111111111111111111111100,
     ];
-    static BITSET_MAPPING: [(u8, u8); 22] = [
-        (0, 64), (1, 188), (1, 186), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66),
-        (1, 70), (1, 77), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), (4, 12), (4, 6),
-        (5, 187), (6, 78), (7, 132),
+    static BITSET_MAPPING: [(u8, u8); 21] = [
+        (0, 64), (1, 184), (1, 182), (1, 179), (1, 172), (1, 161), (1, 146), (1, 144), (1, 140),
+        (1, 136), (1, 132), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), (4, 12),
+        (4, 6), (5, 187), (6, 78),
     ];
 
     pub const fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
+        (c as u32) >= 0xaa &&
         super::bitset_search(
             c as u32,
             &BITSET_CHUNKS_MAP,
@@ -554,43 +577,50 @@ pub mod n {
     use super::ShortOffsetRunHeader;
 
     static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 42] = [
-        ShortOffsetRunHeader::new(0, 1632), ShortOffsetRunHeader::new(9, 2406),
-        ShortOffsetRunHeader::new(15, 4160), ShortOffsetRunHeader::new(49, 4969),
-        ShortOffsetRunHeader::new(53, 5870), ShortOffsetRunHeader::new(55, 6470),
-        ShortOffsetRunHeader::new(63, 8304), ShortOffsetRunHeader::new(79, 9312),
-        ShortOffsetRunHeader::new(89, 10102), ShortOffsetRunHeader::new(93, 11517),
-        ShortOffsetRunHeader::new(95, 12295), ShortOffsetRunHeader::new(97, 12690),
-        ShortOffsetRunHeader::new(103, 42528), ShortOffsetRunHeader::new(115, 43056),
-        ShortOffsetRunHeader::new(119, 44016), ShortOffsetRunHeader::new(131, 65296),
-        ShortOffsetRunHeader::new(133, 65799), ShortOffsetRunHeader::new(135, 66273),
-        ShortOffsetRunHeader::new(141, 67672), ShortOffsetRunHeader::new(153, 68858),
-        ShortOffsetRunHeader::new(183, 69216), ShortOffsetRunHeader::new(189, 70736),
-        ShortOffsetRunHeader::new(209, 71248), ShortOffsetRunHeader::new(213, 71904),
-        ShortOffsetRunHeader::new(221, 72688), ShortOffsetRunHeader::new(225, 73552),
-        ShortOffsetRunHeader::new(233, 74752), ShortOffsetRunHeader::new(237, 90416),
-        ShortOffsetRunHeader::new(239, 92768), ShortOffsetRunHeader::new(241, 93552),
-        ShortOffsetRunHeader::new(249, 93824), ShortOffsetRunHeader::new(251, 118000),
-        ShortOffsetRunHeader::new(253, 119488), ShortOffsetRunHeader::new(255, 120782),
-        ShortOffsetRunHeader::new(261, 123200), ShortOffsetRunHeader::new(263, 123632),
-        ShortOffsetRunHeader::new(265, 124144), ShortOffsetRunHeader::new(267, 125127),
-        ShortOffsetRunHeader::new(271, 126065), ShortOffsetRunHeader::new(275, 127232),
-        ShortOffsetRunHeader::new(285, 130032), ShortOffsetRunHeader::new(287, 1244154),
+        ShortOffsetRunHeader::new(0, 1632), ShortOffsetRunHeader::new(7, 2406),
+        ShortOffsetRunHeader::new(13, 4160), ShortOffsetRunHeader::new(47, 4969),
+        ShortOffsetRunHeader::new(51, 5870), ShortOffsetRunHeader::new(53, 6470),
+        ShortOffsetRunHeader::new(61, 8304), ShortOffsetRunHeader::new(77, 9312),
+        ShortOffsetRunHeader::new(87, 10102), ShortOffsetRunHeader::new(91, 11517),
+        ShortOffsetRunHeader::new(93, 12295), ShortOffsetRunHeader::new(95, 12690),
+        ShortOffsetRunHeader::new(101, 42528), ShortOffsetRunHeader::new(113, 43056),
+        ShortOffsetRunHeader::new(117, 44016), ShortOffsetRunHeader::new(129, 65296),
+        ShortOffsetRunHeader::new(131, 65799), ShortOffsetRunHeader::new(133, 66273),
+        ShortOffsetRunHeader::new(139, 67672), ShortOffsetRunHeader::new(151, 68858),
+        ShortOffsetRunHeader::new(181, 69216), ShortOffsetRunHeader::new(187, 70736),
+        ShortOffsetRunHeader::new(207, 71248), ShortOffsetRunHeader::new(211, 71904),
+        ShortOffsetRunHeader::new(219, 72688), ShortOffsetRunHeader::new(223, 73552),
+        ShortOffsetRunHeader::new(231, 74752), ShortOffsetRunHeader::new(235, 90416),
+        ShortOffsetRunHeader::new(237, 92768), ShortOffsetRunHeader::new(239, 93552),
+        ShortOffsetRunHeader::new(247, 93824), ShortOffsetRunHeader::new(249, 118000),
+        ShortOffsetRunHeader::new(251, 119488), ShortOffsetRunHeader::new(253, 120782),
+        ShortOffsetRunHeader::new(259, 123200), ShortOffsetRunHeader::new(261, 123632),
+        ShortOffsetRunHeader::new(263, 124144), ShortOffsetRunHeader::new(265, 125127),
+        ShortOffsetRunHeader::new(269, 126065), ShortOffsetRunHeader::new(273, 127232),
+        ShortOffsetRunHeader::new(283, 130032), ShortOffsetRunHeader::new(285, 1244154),
     ];
-    static OFFSETS: [u8; 289] = [
-        48, 10, 120, 2, 5, 1, 2, 3, 0, 10, 134, 10, 198, 10, 0, 10, 118, 10, 4, 6, 108, 10, 118,
-        10, 118, 10, 2, 6, 110, 13, 115, 10, 8, 7, 103, 10, 104, 7, 7, 19, 109, 10, 96, 10, 118, 10,
-        70, 20, 0, 10, 70, 10, 0, 20, 0, 3, 239, 10, 6, 10, 22, 10, 0, 10, 128, 11, 165, 10, 6, 10,
-        182, 10, 86, 10, 134, 10, 6, 10, 0, 1, 3, 6, 6, 10, 198, 51, 2, 5, 0, 60, 78, 22, 0, 30, 0,
-        1, 0, 1, 25, 9, 14, 3, 0, 4, 138, 10, 30, 8, 1, 15, 32, 10, 39, 15, 0, 10, 188, 10, 0, 6,
-        154, 10, 38, 10, 198, 10, 22, 10, 86, 10, 0, 10, 0, 10, 0, 45, 12, 57, 17, 2, 0, 27, 36, 4,
-        29, 1, 8, 1, 134, 5, 202, 10, 0, 8, 25, 7, 39, 9, 75, 5, 22, 6, 160, 2, 2, 16, 2, 46, 64, 9,
-        52, 2, 30, 3, 75, 5, 104, 8, 24, 8, 41, 7, 0, 6, 48, 10, 6, 10, 0, 31, 158, 10, 42, 4, 112,
-        7, 134, 30, 128, 10, 60, 10, 144, 10, 7, 20, 251, 10, 0, 10, 118, 10, 0, 10, 102, 10, 6, 20,
-        76, 12, 0, 19, 93, 10, 0, 10, 86, 29, 227, 10, 70, 10, 0, 10, 102, 21, 0, 111, 0, 10, 0, 10,
-        86, 10, 134, 10, 1, 7, 0, 10, 0, 23, 0, 10, 0, 20, 12, 20, 108, 25, 0, 50, 0, 10, 0, 10, 0,
-        10, 247, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0, 10, 0,
+    static OFFSETS: [u8; 287] = [
+        178, 2, 5, 1, 2, 3, 0, 10, 134, 10, 198, 10, 0, 10, 118, 10, 4, 6, 108, 10, 118, 10, 118,
+        10, 2, 6, 110, 13, 115, 10, 8, 7, 103, 10, 104, 7, 7, 19, 109, 10, 96, 10, 118, 10, 70, 20,
+        0, 10, 70, 10, 0, 20, 0, 3, 239, 10, 6, 10, 22, 10, 0, 10, 128, 11, 165, 10, 6, 10, 182, 10,
+        86, 10, 134, 10, 6, 10, 0, 1, 3, 6, 6, 10, 198, 51, 2, 5, 0, 60, 78, 22, 0, 30, 0, 1, 0, 1,
+        25, 9, 14, 3, 0, 4, 138, 10, 30, 8, 1, 15, 32, 10, 39, 15, 0, 10, 188, 10, 0, 6, 154, 10,
+        38, 10, 198, 10, 22, 10, 86, 10, 0, 10, 0, 10, 0, 45, 12, 57, 17, 2, 0, 27, 36, 4, 29, 1, 8,
+        1, 134, 5, 202, 10, 0, 8, 25, 7, 39, 9, 75, 5, 22, 6, 160, 2, 2, 16, 2, 46, 64, 9, 52, 2,
+        30, 3, 75, 5, 104, 8, 24, 8, 41, 7, 0, 6, 48, 10, 6, 10, 0, 31, 158, 10, 42, 4, 112, 7, 134,
+        30, 128, 10, 60, 10, 144, 10, 7, 20, 251, 10, 0, 10, 118, 10, 0, 10, 102, 10, 6, 20, 76, 12,
+        0, 19, 93, 10, 0, 10, 86, 29, 227, 10, 70, 10, 0, 10, 102, 21, 0, 111, 0, 10, 0, 10, 86, 10,
+        134, 10, 1, 7, 0, 10, 0, 23, 0, 10, 0, 20, 12, 20, 108, 25, 0, 50, 0, 10, 0, 10, 0, 10, 247,
+        10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0, 10, 0,
     ];
+    #[inline]
     pub fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
+        (c as u32) >= 0xb2 && lookup_slow(c)
+    }
+
+    #[inline(never)]
+    fn lookup_slow(c: char) -> bool {
         const {
             assert!(SHORT_OFFSET_RUNS.last().unwrap().0 > char::MAX as u32);
             let mut i = 0;
@@ -608,34 +638,34 @@ pub mod n {
 #[rustfmt::skip]
 pub mod uppercase {
     static BITSET_CHUNKS_MAP: [u8; 125] = [
-        12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-        6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-        6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6,
-        6, 6, 9, 6, 3,
+        3, 14, 6, 6, 0, 6, 6, 2, 5, 12, 6, 15, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 6, 6, 7, 6, 13, 6, 11, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 16, 6, 6,
+        6, 6, 10, 6, 4,
     ];
     static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [
-        [44, 44, 5, 35, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 5, 1],
+        [44, 44, 5, 35, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 5, 0],
         [44, 44, 5, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [44, 44, 40, 44, 44, 44, 44, 44, 17, 17, 63, 17, 43, 29, 24, 23],
+        [44, 44, 40, 44, 44, 44, 44, 44, 17, 17, 62, 17, 43, 29, 24, 23],
+        [44, 44, 44, 32, 36, 21, 22, 15, 13, 34, 44, 44, 44, 11, 30, 39],
         [44, 44, 44, 44, 9, 8, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [44, 44, 44, 44, 37, 28, 67, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 44],
+        [44, 44, 44, 44, 37, 28, 66, 44, 44, 44, 44, 44, 44, 44, 44, 44],
         [44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [44, 44, 44, 44, 44, 44, 44, 44, 44, 55, 44, 44, 44, 44, 44, 44],
-        [44, 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 44, 20, 14, 16, 4],
-        [44, 44, 44, 44, 56, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [44, 44, 59, 44, 44, 31, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [44, 44, 60, 46, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [44, 49, 44, 32, 36, 21, 22, 15, 13, 34, 44, 44, 44, 11, 30, 39],
-        [52, 54, 26, 50, 12, 7, 25, 51, 41, 53, 6, 3, 66, 65, 64, 68],
-        [57, 44, 9, 47, 44, 42, 33, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [58, 19, 2, 18, 10, 48, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
-        [58, 38, 17, 27, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
+        [44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 44, 44, 44],
+        [44, 44, 44, 44, 44, 44, 44, 44, 44, 49, 44, 44, 44, 44, 44, 44],
+        [44, 44, 44, 44, 44, 44, 44, 44, 44, 61, 60, 44, 20, 14, 16, 4],
+        [44, 44, 44, 44, 50, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
+        [44, 44, 53, 44, 44, 31, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
+        [44, 44, 54, 46, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
+        [51, 44, 9, 47, 44, 42, 33, 44, 44, 44, 44, 44, 44, 44, 44, 44],
+        [52, 19, 2, 18, 10, 48, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
+        [52, 38, 17, 27, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44],
+        [58, 1, 26, 55, 12, 7, 25, 56, 41, 59, 6, 3, 65, 64, 63, 67],
     ];
     static BITSET_CANONICAL: [u64; 44] = [
-        0b0000011111111111111111111111111000000000000000000000000000000000,
         0b0000000000111111111111111111111111111111111111111111111111111111,
+        0b1111111111111111111111110000000000000000000000000011111111111111,
         0b0101010101010101010101010101010101010101010101010101010000000001,
         0b0000011111111111111111111111110000000000000000000000000000000001,
         0b0000000000100000000000000000000000010101010000010001101011110101,
@@ -679,13 +709,15 @@ pub mod uppercase {
         0b1111011111111111000000000000000000000000000000000000000000000000,
         0b1111111100000000111111110000000000111111000000001111111100000000,
     ];
-    static BITSET_MAPPING: [(u8, u8); 25] = [
-        (0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121),
-        (0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164),
-        (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171),
+    static BITSET_MAPPING: [(u8, u8); 24] = [
+        (0, 182), (0, 74), (0, 166), (0, 162), (0, 159), (0, 150), (0, 148), (0, 142), (0, 134),
+        (0, 131), (0, 64), (1, 66), (1, 70), (1, 83), (1, 12), (1, 8), (2, 164), (2, 146), (2, 20),
+        (3, 146), (3, 140), (3, 134), (4, 178), (4, 171),
     ];
 
     pub const fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
+        (c as u32) >= 0xc0 &&
         super::bitset_search(
             c as u32,
             &BITSET_CHUNKS_MAP,
@@ -699,8 +731,8 @@ pub mod uppercase {
 #[rustfmt::skip]
 pub mod white_space {
     static WHITESPACE_MAP: [u8; 256] = [
-        2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -711,6 +743,7 @@ pub mod white_space {
     ];
     #[inline]
     pub const fn lookup(c: char) -> bool {
+        debug_assert!(!c.is_ascii());
         match c as u32 >> 8 {
             0 => WHITESPACE_MAP[c as usize & 0xff] & 1 != 0,
             22 => c as u32 == 0x1680,
diff --git a/library/coretests/benches/fmt.rs b/library/coretests/benches/fmt.rs
index f45b921b939..17549ab0f1c 100644
--- a/library/coretests/benches/fmt.rs
+++ b/library/coretests/benches/fmt.rs
@@ -342,3 +342,27 @@ fn write_i128_hex(bh: &mut Bencher) {
         black_box(&mut buf).clear();
     });
 }
+
+#[bench]
+fn write_i64_exp(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(1024);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:e}", black_box(0_i64)).unwrap();
+        write!(black_box(&mut buf), "{:e}", black_box(100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:e}", black_box(-100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:e}", black_box(1_i64 << 32)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i128_exp(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(1024);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:e}", black_box(0_i128)).unwrap();
+        write!(black_box(&mut buf), "{:e}", black_box(100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:e}", black_box(-100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:e}", black_box(1_i128 << 64)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs
index c173d7f0ae0..4267fef50f8 100644
--- a/library/coretests/tests/floats/f128.rs
+++ b/library/coretests/tests/floats/f128.rs
@@ -1,7 +1,9 @@
 // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy
 #![cfg(target_has_reliable_f128)]
 
-use super::{assert_approx_eq, assert_biteq};
+#[cfg(any(miri, target_has_reliable_f128_math))]
+use super::assert_approx_eq;
+use super::assert_biteq;
 
 // Note these tolerances make sense around zero, but not for more extreme exponents.
 
@@ -75,25 +77,6 @@ fn test_float_bits_conv() {
 }
 
 #[test]
-fn test_algebraic() {
-    let a: f128 = 123.0;
-    let b: f128 = 456.0;
-
-    // Check that individual operations match their primitive counterparts.
-    //
-    // This is a check of current implementations and does NOT imply any form of
-    // guarantee about future behavior. The compiler reserves the right to make
-    // these operations inexact matches in the future.
-    let eps = if cfg!(miri) { 1e-6 } else { 0.0 };
-
-    assert_approx_eq!(a.algebraic_add(b), a + b, eps);
-    assert_approx_eq!(a.algebraic_sub(b), a - b, eps);
-    assert_approx_eq!(a.algebraic_mul(b), a * b, eps);
-    assert_approx_eq!(a.algebraic_div(b), a / b, eps);
-    assert_approx_eq!(a.algebraic_rem(b), a % b, eps);
-}
-
-#[test]
 fn test_from() {
     assert_biteq!(f128::from(false), 0.0);
     assert_biteq!(f128::from(true), 1.0);
diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs
index c12de7221ba..d2818a6d768 100644
--- a/library/coretests/tests/floats/f16.rs
+++ b/library/coretests/tests/floats/f16.rs
@@ -74,27 +74,6 @@ fn test_float_bits_conv() {
 }
 
 #[test]
-fn test_algebraic() {
-    let a: f16 = 123.0;
-    let b: f16 = 456.0;
-
-    // Check that individual operations match their primitive counterparts.
-    //
-    // This is a check of current implementations and does NOT imply any form of
-    // guarantee about future behavior. The compiler reserves the right to make
-    // these operations inexact matches in the future.
-    let eps_add = if cfg!(miri) { 1e1 } else { 0.0 };
-    let eps_mul = if cfg!(miri) { 1e3 } else { 0.0 };
-    let eps_div = if cfg!(miri) { 1e0 } else { 0.0 };
-
-    assert_approx_eq!(a.algebraic_add(b), a + b, eps_add);
-    assert_approx_eq!(a.algebraic_sub(b), a - b, eps_add);
-    assert_approx_eq!(a.algebraic_mul(b), a * b, eps_mul);
-    assert_approx_eq!(a.algebraic_div(b), a / b, eps_div);
-    assert_approx_eq!(a.algebraic_rem(b), a % b, eps_div);
-}
-
-#[test]
 fn test_from() {
     assert_biteq!(f16::from(false), 0.0);
     assert_biteq!(f16::from(true), 1.0);
diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs
index b79295f470d..7b25f354da4 100644
--- a/library/coretests/tests/floats/f32.rs
+++ b/library/coretests/tests/floats/f32.rs
@@ -1,6 +1,6 @@
 use core::f32;
 
-use super::{assert_approx_eq, assert_biteq};
+use super::assert_biteq;
 
 /// First pattern over the mantissa
 const NAN_MASK1: u32 = 0x002a_aaaa;
@@ -47,24 +47,3 @@ fn test_float_bits_conv() {
     assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
     assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
 }
-
-#[test]
-fn test_algebraic() {
-    let a: f32 = 123.0;
-    let b: f32 = 456.0;
-
-    // Check that individual operations match their primitive counterparts.
-    //
-    // This is a check of current implementations and does NOT imply any form of
-    // guarantee about future behavior. The compiler reserves the right to make
-    // these operations inexact matches in the future.
-    let eps_add = if cfg!(miri) { 1e-3 } else { 0.0 };
-    let eps_mul = if cfg!(miri) { 1e-1 } else { 0.0 };
-    let eps_div = if cfg!(miri) { 1e-4 } else { 0.0 };
-
-    assert_approx_eq!(a.algebraic_add(b), a + b, eps_add);
-    assert_approx_eq!(a.algebraic_sub(b), a - b, eps_add);
-    assert_approx_eq!(a.algebraic_mul(b), a * b, eps_mul);
-    assert_approx_eq!(a.algebraic_div(b), a / b, eps_div);
-    assert_approx_eq!(a.algebraic_rem(b), a % b, eps_div);
-}
diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs
index a2540586328..099d85627a3 100644
--- a/library/coretests/tests/floats/f64.rs
+++ b/library/coretests/tests/floats/f64.rs
@@ -1,6 +1,6 @@
 use core::f64;
 
-use super::{assert_approx_eq, assert_biteq};
+use super::assert_biteq;
 
 /// First pattern over the mantissa
 const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa;
@@ -46,22 +46,3 @@ fn test_float_bits_conv() {
     assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
     assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
 }
-
-#[test]
-fn test_algebraic() {
-    let a: f64 = 123.0;
-    let b: f64 = 456.0;
-
-    // Check that individual operations match their primitive counterparts.
-    //
-    // This is a check of current implementations and does NOT imply any form of
-    // guarantee about future behavior. The compiler reserves the right to make
-    // these operations inexact matches in the future.
-    let eps = if cfg!(miri) { 1e-6 } else { 0.0 };
-
-    assert_approx_eq!(a.algebraic_add(b), a + b, eps);
-    assert_approx_eq!(a.algebraic_sub(b), a - b, eps);
-    assert_approx_eq!(a.algebraic_mul(b), a * b, eps);
-    assert_approx_eq!(a.algebraic_div(b), a / b, eps);
-    assert_approx_eq!(a.algebraic_rem(b), a % b, eps);
-}
diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs
index 5f59cb9cce3..c0439845a4a 100644
--- a/library/coretests/tests/floats/mod.rs
+++ b/library/coretests/tests/floats/mod.rs
@@ -27,6 +27,9 @@ trait TestableFloat: Sized {
     const NAN_MASK1: Self::Int;
     /// Second pattern over the mantissa
     const NAN_MASK2: Self::Int;
+    const EPS_ADD: Self;
+    const EPS_MUL: Self;
+    const EPS_DIV: Self;
 }
 
 impl TestableFloat for f16 {
@@ -44,6 +47,9 @@ impl TestableFloat for f16 {
     const MAX_DOWN: Self = Self::from_bits(0x7bfe);
     const NAN_MASK1: Self::Int = 0x02aa;
     const NAN_MASK2: Self::Int = 0x0155;
+    const EPS_ADD: Self = if cfg!(miri) { 1e1 } else { 0.0 };
+    const EPS_MUL: Self = if cfg!(miri) { 1e3 } else { 0.0 };
+    const EPS_DIV: Self = if cfg!(miri) { 1e0 } else { 0.0 };
 }
 
 impl TestableFloat for f32 {
@@ -63,6 +69,9 @@ impl TestableFloat for f32 {
     const MAX_DOWN: Self = Self::from_bits(0x7f7f_fffe);
     const NAN_MASK1: Self::Int = 0x002a_aaaa;
     const NAN_MASK2: Self::Int = 0x0055_5555;
+    const EPS_ADD: Self = if cfg!(miri) { 1e-3 } else { 0.0 };
+    const EPS_MUL: Self = if cfg!(miri) { 1e-1 } else { 0.0 };
+    const EPS_DIV: Self = if cfg!(miri) { 1e-4 } else { 0.0 };
 }
 
 impl TestableFloat for f64 {
@@ -78,6 +87,9 @@ impl TestableFloat for f64 {
     const MAX_DOWN: Self = Self::from_bits(0x7fef_ffff_ffff_fffe);
     const NAN_MASK1: Self::Int = 0x000a_aaaa_aaaa_aaaa;
     const NAN_MASK2: Self::Int = 0x0005_5555_5555_5555;
+    const EPS_ADD: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
+    const EPS_MUL: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
+    const EPS_DIV: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
 }
 
 impl TestableFloat for f128 {
@@ -93,6 +105,9 @@ impl TestableFloat for f128 {
     const MAX_DOWN: Self = Self::from_bits(0x7ffefffffffffffffffffffffffffffe);
     const NAN_MASK1: Self::Int = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa;
     const NAN_MASK2: Self::Int = 0x00005555555555555555555555555555;
+    const EPS_ADD: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
+    const EPS_MUL: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
+    const EPS_DIV: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
 }
 
 /// Determine the tolerance for values of the argument type.
@@ -1440,3 +1455,27 @@ float_test! {
         assert_biteq!(neg_inf.to_radians(), neg_inf);
     }
 }
+
+float_test! {
+    name: to_algebraic,
+    attrs: {
+        f16: #[cfg(target_has_reliable_f16)],
+        f128: #[cfg(target_has_reliable_f128)],
+    },
+    test<Float> {
+        let a: Float = 123.0;
+        let b: Float = 456.0;
+
+        // Check that individual operations match their primitive counterparts.
+        //
+        // This is a check of current implementations and does NOT imply any form of
+        // guarantee about future behavior. The compiler reserves the right to make
+        // these operations inexact matches in the future.
+
+        assert_approx_eq!(a.algebraic_add(b), a + b, Float::EPS_ADD);
+        assert_approx_eq!(a.algebraic_sub(b), a - b, Float::EPS_ADD);
+        assert_approx_eq!(a.algebraic_mul(b), a * b, Float::EPS_MUL);
+        assert_approx_eq!(a.algebraic_div(b), a / b, Float::EPS_DIV);
+        assert_approx_eq!(a.algebraic_rem(b), a % b, Float::EPS_DIV);
+    }
+}
diff --git a/library/coretests/tests/iter/adapters/peekable.rs b/library/coretests/tests/iter/adapters/peekable.rs
index 7f4341b8902..f0549e8d6c2 100644
--- a/library/coretests/tests/iter/adapters/peekable.rs
+++ b/library/coretests/tests/iter/adapters/peekable.rs
@@ -271,3 +271,89 @@ fn test_peekable_non_fused() {
     assert_eq!(iter.peek(), None);
     assert_eq!(iter.next_back(), None);
 }
+
+#[test]
+fn test_peekable_next_if_map_mutation() {
+    fn collatz((mut num, mut len): (u64, u32)) -> Result<u32, (u64, u32)> {
+        let jump = num.trailing_zeros();
+        num >>= jump;
+        len += jump;
+        if num == 1 { Ok(len) } else { Err((3 * num + 1, len + 1)) }
+    }
+
+    let mut iter = once((3, 0)).peekable();
+    assert_eq!(iter.peek(), Some(&(3, 0)));
+    assert_eq!(iter.next_if_map(collatz), None);
+    assert_eq!(iter.peek(), Some(&(10, 1)));
+    assert_eq!(iter.next_if_map(collatz), None);
+    assert_eq!(iter.peek(), Some(&(16, 3)));
+    assert_eq!(iter.next_if_map(collatz), Some(7));
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.next_if_map(collatz), None);
+}
+
+#[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+fn test_peekable_next_if_map_panic() {
+    use core::cell::Cell;
+    use std::panic::{AssertUnwindSafe, catch_unwind};
+
+    struct BitsetOnDrop<'a> {
+        value: u32,
+        cell: &'a Cell<u32>,
+    }
+    impl<'a> Drop for BitsetOnDrop<'a> {
+        fn drop(&mut self) {
+            self.cell.update(|v| v | self.value);
+        }
+    }
+
+    let cell = &Cell::new(0);
+    let mut it = [
+        BitsetOnDrop { value: 1, cell },
+        BitsetOnDrop { value: 2, cell },
+        BitsetOnDrop { value: 4, cell },
+        BitsetOnDrop { value: 8, cell },
+    ]
+    .into_iter()
+    .peekable();
+
+    // sanity check, .peek() won't consume the value, .next() will transfer ownership.
+    let item = it.peek().unwrap();
+    assert_eq!(item.value, 1);
+    assert_eq!(cell.get(), 0);
+    let item = it.next().unwrap();
+    assert_eq!(item.value, 1);
+    assert_eq!(cell.get(), 0);
+    drop(item);
+    assert_eq!(cell.get(), 1);
+
+    // next_if_map returning Ok should transfer the value out.
+    let item = it.next_if_map(Ok).unwrap();
+    assert_eq!(item.value, 2);
+    assert_eq!(cell.get(), 1);
+    drop(item);
+    assert_eq!(cell.get(), 3);
+
+    // next_if_map returning Err should not drop anything.
+    assert_eq!(it.next_if_map::<()>(Err), None);
+    assert_eq!(cell.get(), 3);
+    assert_eq!(it.peek().unwrap().value, 4);
+    assert_eq!(cell.get(), 3);
+
+    // next_if_map panicking should consume and drop the item.
+    let result = catch_unwind({
+        let mut it = AssertUnwindSafe(&mut it);
+        move || it.next_if_map::<()>(|_| panic!())
+    });
+    assert!(result.is_err());
+    assert_eq!(cell.get(), 7);
+    assert_eq!(it.next().unwrap().value, 8);
+    assert_eq!(cell.get(), 15);
+    assert!(it.peek().is_none());
+
+    // next_if_map should *not* execute the closure if the iterator is exhausted.
+    assert!(it.next_if_map::<()>(|_| panic!()).is_none());
+    assert!(it.peek().is_none());
+    assert_eq!(cell.get(), 15);
+}
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index ffb96b5a7cf..b5658a9970f 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -50,6 +50,7 @@
 #![feature(fmt_internals)]
 #![feature(formatting_options)]
 #![feature(freeze)]
+#![feature(funnel_shifts)]
 #![feature(future_join)]
 #![feature(generic_assert_internals)]
 #![feature(hasher_prefixfree_extras)]
@@ -82,6 +83,7 @@
 #![feature(numfmt)]
 #![feature(option_reduce)]
 #![feature(pattern)]
+#![feature(peekable_next_if_map)]
 #![feature(pointer_is_aligned_to)]
 #![feature(portable_simd)]
 #![feature(ptr_metadata)]
diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs
index c7d10ea4d88..63be8a45b5c 100644
--- a/library/coretests/tests/num/uint_macros.rs
+++ b/library/coretests/tests/num/uint_macros.rs
@@ -104,6 +104,19 @@ macro_rules! uint_module {
                 assert_eq_const_safe!($T: C.rotate_left(128), C);
             }
 
+            fn test_funnel_shift() {
+                // Shifting by 0 should have no effect
+                assert_eq_const_safe!($T: <$T>::funnel_shl(A, B, 0), A);
+                assert_eq_const_safe!($T: <$T>::funnel_shr(A, B, 0), B);
+
+                assert_eq_const_safe!($T: <$T>::funnel_shl(_0, _1, 4), 0b1111);
+                assert_eq_const_safe!($T: <$T>::funnel_shr(_0, _1, 4), _1 >> 4);
+                assert_eq_const_safe!($T: <$T>::funnel_shl(_1, _0, 4), _1 << 4);
+
+                assert_eq_const_safe!($T: <$T>::funnel_shl(_1, _1, 4), <$T>::rotate_left(_1, 4));
+                assert_eq_const_safe!($T: <$T>::funnel_shr(_1, _1, 4), <$T>::rotate_right(_1, 4));
+            }
+
             fn test_swap_bytes() {
                 assert_eq_const_safe!($T: A.swap_bytes().swap_bytes(), A);
                 assert_eq_const_safe!($T: B.swap_bytes().swap_bytes(), B);
@@ -151,6 +164,29 @@ macro_rules! uint_module {
         }
 
         #[test]
+        #[should_panic = "attempt to funnel shift left with overflow"]
+        fn test_funnel_shl_overflow() {
+            let _ = <$T>::funnel_shl(A, B, $T::BITS);
+        }
+
+        #[test]
+        #[should_panic = "attempt to funnel shift right with overflow"]
+        fn test_funnel_shr_overflow() {
+            let _ = <$T>::funnel_shr(A, B, $T::BITS);
+        }
+
+        #[test]
+        fn test_funnel_shifts_runtime() {
+            for i in 0..$T::BITS - 1 {
+                assert_eq!(<$T>::funnel_shl(A, 0, i), A << i);
+                assert_eq!(<$T>::funnel_shl(A, A, i), A.rotate_left(i));
+
+                assert_eq!(<$T>::funnel_shr(0, A, i), A >> i);
+                assert_eq!(<$T>::funnel_shr(A, A, i), A.rotate_right(i));
+            }
+        }
+
+        #[test]
         fn test_isolate_highest_one() {
             const BITS: $T = <$T>::MAX;
             const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1);
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/int.rs b/library/portable-simd/crates/core_simd/src/simd/num/int.rs
index d25050c3e4b..e7253313f03 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/int.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/int.rs
@@ -58,6 +58,7 @@ pub trait SimdInt: Copy + Sealed {
     /// let sat = x.saturating_sub(max);
     /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
     /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
+    /// ```
     fn saturating_sub(self, second: Self) -> Self;
 
     /// Lanewise absolute value, implemented in Rust.
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
index 45d978068b6..e3ba8658bd8 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
@@ -55,6 +55,7 @@ pub trait SimdUint: Copy + Sealed {
     /// let sat = x.saturating_sub(max);
     /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
     /// assert_eq!(sat, Simd::splat(0));
+    /// ```
     fn saturating_sub(self, second: Self) -> Self;
 
     /// Lanewise absolute difference.
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 8b78fe53a39..d28a7f0b460 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -81,7 +81,7 @@ wasi = { version = "0.11.0", features = [
 ], default-features = false }
 
 [target.'cfg(all(target_os = "wasi", target_env = "p2"))'.dependencies]
-wasip2 = { version = '0.14.3', features = [
+wasip2 = { version = '0.14.4', features = [
     'rustc-dep-of-std',
 ], default-features = false, package = 'wasi' }
 
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 5e51d5e5211..f8dfb0d6334 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -226,6 +226,7 @@ fn file_test_io_seek_and_write() {
     target_os = "freebsd",
     target_os = "linux",
     target_os = "netbsd",
+    target_os = "solaris",
     target_vendor = "apple",
 ))]
 fn file_lock_multiple_shared() {
@@ -249,6 +250,7 @@ fn file_lock_multiple_shared() {
     target_os = "freebsd",
     target_os = "linux",
     target_os = "netbsd",
+    target_os = "solaris",
     target_vendor = "apple",
 ))]
 fn file_lock_blocking() {
@@ -273,6 +275,7 @@ fn file_lock_blocking() {
     target_os = "freebsd",
     target_os = "linux",
     target_os = "netbsd",
+    target_os = "solaris",
     target_vendor = "apple",
 ))]
 fn file_lock_drop() {
@@ -294,6 +297,7 @@ fn file_lock_drop() {
     target_os = "freebsd",
     target_os = "linux",
     target_os = "netbsd",
+    target_os = "solaris",
     target_vendor = "apple",
 ))]
 fn file_lock_dup() {
@@ -492,6 +496,85 @@ fn file_test_io_read_write_at() {
 
 #[test]
 #[cfg(unix)]
+fn test_read_buf_at() {
+    use crate::os::unix::fs::FileExt;
+
+    let tmpdir = tmpdir();
+    let filename = tmpdir.join("file_rt_io_file_test_read_buf_at.txt");
+    {
+        let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+        let mut file = check!(oo.open(&filename));
+        check!(file.write_all(b"0123456789"));
+    }
+    {
+        let mut file = check!(File::open(&filename));
+        let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
+        let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+
+        // Fill entire buffer with potentially short reads
+        while buf.unfilled().capacity() > 0 {
+            let len = buf.len();
+            check!(file.read_buf_at(buf.unfilled(), 2 + len as u64));
+            assert!(!buf.filled().is_empty());
+            assert!(b"23456".starts_with(buf.filled()));
+            assert_eq!(check!(file.stream_position()), 0);
+        }
+        assert_eq!(buf.filled(), b"23456");
+
+        // Already full
+        check!(file.read_buf_at(buf.unfilled(), 3));
+        check!(file.read_buf_at(buf.unfilled(), 10));
+        assert_eq!(buf.filled(), b"23456");
+        assert_eq!(check!(file.stream_position()), 0);
+
+        // Read past eof is noop
+        check!(file.read_buf_at(buf.clear().unfilled(), 10));
+        assert_eq!(buf.filled(), b"");
+        check!(file.read_buf_at(buf.clear().unfilled(), 11));
+        assert_eq!(buf.filled(), b"");
+        assert_eq!(check!(file.stream_position()), 0);
+    }
+    check!(fs::remove_file(&filename));
+}
+
+#[test]
+#[cfg(unix)]
+fn test_read_buf_exact_at() {
+    use crate::os::unix::fs::FileExt;
+
+    let tmpdir = tmpdir();
+    let filename = tmpdir.join("file_rt_io_file_test_read_buf_exact_at.txt");
+    {
+        let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+        let mut file = check!(oo.open(&filename));
+        check!(file.write_all(b"0123456789"));
+    }
+    {
+        let mut file = check!(File::open(&filename));
+        let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
+        let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+
+        // Exact read
+        check!(file.read_buf_exact_at(buf.unfilled(), 2));
+        assert_eq!(buf.filled(), b"23456");
+        assert_eq!(check!(file.stream_position()), 0);
+
+        // Already full
+        check!(file.read_buf_exact_at(buf.unfilled(), 3));
+        check!(file.read_buf_exact_at(buf.unfilled(), 10));
+        assert_eq!(buf.filled(), b"23456");
+        assert_eq!(check!(file.stream_position()), 0);
+
+        // Non-empty exact read past eof fails
+        let err = file.read_buf_exact_at(buf.clear().unfilled(), 6).unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::UnexpectedEof);
+        assert_eq!(check!(file.stream_position()), 0);
+    }
+    check!(fs::remove_file(&filename));
+}
+
+#[test]
+#[cfg(unix)]
 fn set_get_unix_permissions() {
     use crate::os::unix::fs::PermissionsExt;
 
@@ -567,6 +650,39 @@ fn file_test_io_seek_read_write() {
 }
 
 #[test]
+#[cfg(windows)]
+fn test_seek_read_buf() {
+    use crate::os::windows::fs::FileExt;
+
+    let tmpdir = tmpdir();
+    let filename = tmpdir.join("file_rt_io_file_test_seek_read_buf.txt");
+    {
+        let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+        let mut file = check!(oo.open(&filename));
+        check!(file.write_all(b"0123456789"));
+    }
+    {
+        let mut file = check!(File::open(&filename));
+        let mut buf: [MaybeUninit<u8>; 1] = [MaybeUninit::uninit()];
+        let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+
+        // Seek read
+        check!(file.seek_read_buf(buf.unfilled(), 8));
+        assert_eq!(buf.filled(), b"8");
+        assert_eq!(check!(file.stream_position()), 9);
+
+        // Empty seek read
+        check!(file.seek_read_buf(buf.unfilled(), 0));
+        assert_eq!(buf.filled(), b"8");
+
+        // Seek read past eof
+        check!(file.seek_read_buf(buf.clear().unfilled(), 10));
+        assert_eq!(buf.filled(), b"");
+    }
+    check!(fs::remove_file(&filename));
+}
+
+#[test]
 fn file_test_read_buf() {
     let tmpdir = tmpdir();
     let filename = &tmpdir.join("test");
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index a4b63462053..97db0d6ab75 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -294,6 +294,7 @@
 #![feature(f128)]
 #![feature(ffi_const)]
 #![feature(formatting_options)]
+#![feature(funnel_shifts)]
 #![feature(hash_map_internals)]
 #![feature(hash_map_macro)]
 #![feature(if_let_guard)]
@@ -353,6 +354,7 @@
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
 #![feature(hint_must_use)]
+#![feature(int_from_ascii)]
 #![feature(ip)]
 #![feature(lazy_get)]
 #![feature(maybe_uninit_slice)]
@@ -368,6 +370,7 @@
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(slice_range)]
+#![feature(slice_split_once)]
 #![feature(std_internals)]
 #![feature(str_internals)]
 #![feature(sync_unsafe_cell)]
diff --git a/library/std/src/num/f128.rs b/library/std/src/num/f128.rs
index 64e604e35f7..b83692390b6 100644
--- a/library/std/src/num/f128.rs
+++ b/library/std/src/num/f128.rs
@@ -467,10 +467,10 @@ impl f128 {
     /// # #[cfg(not(miri))]
     /// # #[cfg(target_has_reliable_f128_math)] {
     ///
-    /// let f = std::f128::consts::FRAC_PI_2;
+    /// let f = std::f128::consts::FRAC_PI_4;
     ///
     /// // asin(sin(pi/2))
-    /// let abs_difference = (f.sin().asin() - std::f128::consts::FRAC_PI_2).abs();
+    /// let abs_difference = (f.sin().asin() - f).abs();
     ///
     /// assert!(abs_difference <= f128::EPSILON);
     /// # }
@@ -912,10 +912,10 @@ impl f128 {
     /// # #[cfg(not(miri))]
     /// # #[cfg(target_has_reliable_f128_math)] {
     ///
-    /// let e = std::f128::consts::E;
-    /// let f = e.tanh().atanh();
+    /// let x = std::f128::consts::FRAC_PI_6;
+    /// let f = x.tanh().atanh();
     ///
-    /// let abs_difference = (f - e).abs();
+    /// let abs_difference = (f - x).abs();
     ///
     /// assert!(abs_difference <= 1e-5);
     /// # }
diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs
index 7bdefb05858..5599528717c 100644
--- a/library/std/src/num/f16.rs
+++ b/library/std/src/num/f16.rs
@@ -432,10 +432,10 @@ impl f16 {
     /// # #[cfg(not(miri))]
     /// # #[cfg(target_has_reliable_f16_math)] {
     ///
-    /// let f = std::f16::consts::FRAC_PI_2;
+    /// let f = std::f16::consts::FRAC_PI_4;
     ///
     /// // asin(sin(pi/2))
-    /// let abs_difference = (f.sin().asin() - std::f16::consts::FRAC_PI_2).abs();
+    /// let abs_difference = (f.sin().asin() - f).abs();
     ///
     /// assert!(abs_difference <= f16::EPSILON);
     /// # }
@@ -877,10 +877,10 @@ impl f16 {
     /// # #[cfg(not(miri))]
     /// # #[cfg(target_has_reliable_f16_math)] {
     ///
-    /// let e = std::f16::consts::E;
-    /// let f = e.tanh().atanh();
+    /// let x = std::f16::consts::FRAC_PI_6;
+    /// let f = x.tanh().atanh();
     ///
-    /// let abs_difference = (f - e).abs();
+    /// let abs_difference = (f - x).abs();
     ///
     /// assert!(abs_difference <= 0.01);
     /// # }
diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs
index 5dee68ad909..0247080a8d6 100644
--- a/library/std/src/num/f32.rs
+++ b/library/std/src/num/f32.rs
@@ -582,8 +582,8 @@ impl f32 {
     /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
     /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
     ///
-    /// assert!(abs_difference_x <= f32::EPSILON);
-    /// assert!(abs_difference_y <= f32::EPSILON);
+    /// assert!(abs_difference_x <= 1e-6);
+    /// assert!(abs_difference_y <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -621,7 +621,7 @@ impl f32 {
     /// // x^(1/3) - 2 == 0
     /// let abs_difference = (x.cbrt() - 2.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -652,7 +652,7 @@ impl f32 {
     /// // sqrt(x^2 + y^2)
     /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= 1e-5);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -725,7 +725,7 @@ impl f32 {
     /// let x = std::f32::consts::FRAC_PI_4;
     /// let abs_difference = (x.tan() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -749,12 +749,12 @@ impl f32 {
     /// # Examples
     ///
     /// ```
-    /// let f = std::f32::consts::FRAC_PI_2;
+    /// let f = std::f32::consts::FRAC_PI_4;
     ///
     /// // asin(sin(pi/2))
-    /// let abs_difference = (f.sin().asin() - std::f32::consts::FRAC_PI_2).abs();
+    /// let abs_difference = (f.sin().asin() - f).abs();
     ///
-    /// assert!(abs_difference <= 1e-3);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[doc(alias = "arcsin")]
     #[rustc_allow_incoherent_impl]
@@ -813,7 +813,7 @@ impl f32 {
     /// // atan(tan(1))
     /// let abs_difference = (f.tan().atan() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[doc(alias = "arctan")]
     #[rustc_allow_incoherent_impl]
@@ -854,8 +854,8 @@ impl f32 {
     /// let abs_difference_1 = (y1.atan2(x1) - (-std::f32::consts::FRAC_PI_4)).abs();
     /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f32::consts::FRAC_PI_4)).abs();
     ///
-    /// assert!(abs_difference_1 <= f32::EPSILON);
-    /// assert!(abs_difference_2 <= f32::EPSILON);
+    /// assert!(abs_difference_1 <= 1e-5);
+    /// assert!(abs_difference_2 <= 1e-5);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -884,8 +884,8 @@ impl f32 {
     /// let abs_difference_0 = (f.0 - x.sin()).abs();
     /// let abs_difference_1 = (f.1 - x.cos()).abs();
     ///
-    /// assert!(abs_difference_0 <= 1e-6);
-    /// assert!(abs_difference_1 <= 1e-6);
+    /// assert!(abs_difference_0 <= 1e-4);
+    /// assert!(abs_difference_1 <= 1e-4);
     /// ```
     #[doc(alias = "sincos")]
     #[rustc_allow_incoherent_impl]
@@ -982,7 +982,7 @@ impl f32 {
     /// let g = ((e * e) - 1.0) / (2.0 * e);
     /// let abs_difference = (f - g).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1012,7 +1012,7 @@ impl f32 {
     /// let abs_difference = (f - g).abs();
     ///
     /// // Same result
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1042,7 +1042,7 @@ impl f32 {
     /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2));
     /// let abs_difference = (f - g).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1067,7 +1067,7 @@ impl f32 {
     ///
     /// let abs_difference = (f - x).abs();
     ///
-    /// assert!(abs_difference <= 1e-7);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[doc(alias = "arcsinh")]
     #[rustc_allow_incoherent_impl]
@@ -1120,10 +1120,10 @@ impl f32 {
     /// # Examples
     ///
     /// ```
-    /// let e = std::f32::consts::E;
-    /// let f = e.tanh().atanh();
+    /// let x = std::f32::consts::FRAC_PI_6;
+    /// let f = x.tanh().atanh();
     ///
-    /// let abs_difference = (f - e).abs();
+    /// let abs_difference = (f - x).abs();
     ///
     /// assert!(abs_difference <= 1e-5);
     /// ```
@@ -1153,7 +1153,7 @@ impl f32 {
     ///
     /// let abs_difference = (x.gamma() - 24.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-5);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1248,7 +1248,7 @@ impl f32 {
     /// let one = x.erf() + x.erfc();
     /// let abs_difference = (one - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs
index 3ec80f68bdb..1cfd3909d96 100644
--- a/library/std/src/num/f64.rs
+++ b/library/std/src/num/f64.rs
@@ -749,12 +749,12 @@ impl f64 {
     /// # Examples
     ///
     /// ```
-    /// let f = std::f64::consts::FRAC_PI_2;
+    /// let f = std::f64::consts::FRAC_PI_4;
     ///
     /// // asin(sin(pi/2))
-    /// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs();
+    /// let abs_difference = (f.sin().asin() - f).abs();
     ///
-    /// assert!(abs_difference < 1e-7);
+    /// assert!(abs_difference < 1e-14);
     /// ```
     #[doc(alias = "arcsin")]
     #[rustc_allow_incoherent_impl]
@@ -1120,10 +1120,10 @@ impl f64 {
     /// # Examples
     ///
     /// ```
-    /// let e = std::f64::consts::E;
-    /// let f = e.tanh().atanh();
+    /// let x = std::f64::consts::FRAC_PI_6;
+    /// let f = x.tanh().atanh();
     ///
-    /// let abs_difference = (f - e).abs();
+    /// let abs_difference = (f - x).abs();
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
@@ -1153,7 +1153,7 @@ impl f64 {
     ///
     /// let abs_difference = (x.gamma() - 24.0).abs();
     ///
-    /// assert!(abs_difference <= f64::EPSILON);
+    /// assert!(abs_difference <= 1e-10);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1248,7 +1248,7 @@ impl f64 {
     /// let one = x.erf() + x.erfc();
     /// let abs_difference = (one - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f64::EPSILON);
+    /// assert!(abs_difference <= 1e-10);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/library/std/src/os/cygwin/mod.rs b/library/std/src/os/cygwin/mod.rs
index 7f6d6a645c8..a295a07caac 100644
--- a/library/std/src/os/cygwin/mod.rs
+++ b/library/std/src/os/cygwin/mod.rs
@@ -1,4 +1,5 @@
 //! Cygwin-specific definitions
 #![stable(feature = "raw_ext", since = "1.1.0")]
 pub mod fs;
+pub mod net;
 pub(crate) mod raw;
diff --git a/library/std/src/os/cygwin/net.rs b/library/std/src/os/cygwin/net.rs
new file mode 100644
index 00000000000..0cccddb85d0
--- /dev/null
+++ b/library/std/src/os/cygwin/net.rs
@@ -0,0 +1,17 @@
+//! Cygwin-specific networking functionality.
+//!
+//! There are some limitations of Unix domain sockets on Cygwin:
+//! * The syscalls `accept` and `connect` need
+//! [handshake](https://inbox.sourceware.org/cygwin/Z_UERXFI1g-1v3p2@calimero.vinschen.de/T/#t).
+//! * Cannot bind to abstract addr.
+//! * Unbounded unix socket has an abstract local addr.
+//! * Doesn't support recvmsg with control data.
+
+#![stable(feature = "unix_socket_abstract", since = "1.70.0")]
+
+#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
+pub use crate::os::net::linux_ext::addr::SocketAddrExt;
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub use crate::os::net::linux_ext::socket::UnixSocketExt;
+#[stable(feature = "tcp_quickack", since = "1.89.0")]
+pub use crate::os::net::linux_ext::tcp::TcpStreamExt;
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index ab7734a7952..96d9bfae8ca 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -185,5 +185,5 @@ pub mod xous;
 #[cfg(any(unix, target_os = "hermit", target_os = "trusty", target_os = "wasi", doc))]
 pub mod fd;
 
-#[cfg(any(target_os = "linux", target_os = "android", doc))]
+#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))]
 mod net;
diff --git a/library/std/src/os/net/linux_ext/mod.rs b/library/std/src/os/net/linux_ext/mod.rs
index 3c9afe35479..f3f3fdd258c 100644
--- a/library/std/src/os/net/linux_ext/mod.rs
+++ b/library/std/src/os/net/linux_ext/mod.rs
@@ -1,6 +1,6 @@
-//! Linux and Android-specific networking functionality.
+//! Linux, Android and Cygwin-specific networking functionality.
 
-#![doc(cfg(any(target_os = "linux", target_os = "android")))]
+#![doc(cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin")))]
 
 #[stable(feature = "unix_socket_abstract", since = "1.70.0")]
 pub(crate) mod addr;
diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs
index b7046dd7c59..47e69b3a260 100644
--- a/library/std/src/os/net/mod.rs
+++ b/library/std/src/os/net/mod.rs
@@ -9,5 +9,5 @@
         all(target_vendor = "fortanix", target_env = "sgx")
     )
 )))]
-#[cfg(any(target_os = "linux", target_os = "android", doc))]
+#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))]
 pub(super) mod linux_ext;
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index b776df3dde1..1d1a138b302 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -11,6 +11,7 @@ use super::platform::fs::MetadataExt as _;
 // Used for `File::read` on intra-doc links
 use crate::ffi::OsStr;
 use crate::fs::{self, OpenOptions, Permissions};
+use crate::io::BorrowedCursor;
 use crate::os::unix::io::{AsFd, AsRawFd};
 use crate::path::Path;
 use crate::sealed::Sealed;
@@ -130,6 +131,91 @@ pub trait FileExt {
         if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
     }
 
+    /// Reads some bytes starting from a given offset into the buffer.
+    ///
+    /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a
+    /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new
+    /// data will be appended to any existing contents of `buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(core_io_borrowed_buf)]
+    /// #![feature(read_buf_at)]
+    ///
+    /// use std::io;
+    /// use std::io::BorrowedBuf;
+    /// use std::fs::File;
+    /// use std::mem::MaybeUninit;
+    /// use std::os::unix::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("pi.txt")?;
+    ///
+    ///     // Read some bytes starting from offset 2
+    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
+    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    ///     file.read_buf_at(buf.unfilled(), 2)?;
+    ///
+    ///     assert!(buf.filled().starts_with(b"1"));
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "read_buf_at", issue = "140771")]
+    fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        io::default_read_buf(|b| self.read_at(b, offset), buf)
+    }
+
+    /// Reads the exact number of bytes required to fill the buffer from a given offset.
+    ///
+    /// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method, except that it
+    /// is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized
+    /// buffers. The new data will be appended to any existing contents of `buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(core_io_borrowed_buf)]
+    /// #![feature(read_buf_at)]
+    ///
+    /// use std::io;
+    /// use std::io::BorrowedBuf;
+    /// use std::fs::File;
+    /// use std::mem::MaybeUninit;
+    /// use std::os::unix::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("pi.txt")?;
+    ///
+    ///     // Read exactly 10 bytes starting from offset 2
+    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
+    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    ///     file.read_buf_exact_at(buf.unfilled(), 2)?;
+    ///
+    ///     assert_eq!(buf.filled(), b"1415926535");
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "read_buf_at", issue = "140771")]
+    fn read_buf_exact_at(&self, mut buf: BorrowedCursor<'_>, mut offset: u64) -> io::Result<()> {
+        while buf.capacity() > 0 {
+            let prev_written = buf.written();
+            match self.read_buf_at(buf.reborrow(), offset) {
+                Ok(()) => {}
+                Err(e) if e.is_interrupted() => {}
+                Err(e) => return Err(e),
+            }
+            let n = buf.written() - prev_written;
+            offset += n as u64;
+            if n == 0 {
+                return Err(io::Error::READ_EXACT_EOF);
+            }
+        }
+        Ok(())
+    }
+
     /// Writes a number of bytes starting from a given offset.
     ///
     /// Returns the number of bytes written.
@@ -264,6 +350,9 @@ impl FileExt for fs::File {
     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.as_inner().read_at(buf, offset)
     }
+    fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.as_inner().read_buf_at(buf, offset)
+    }
     fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
         self.as_inner().read_vectored_at(bufs, offset)
     }
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index fd6fe72dd24..25b95014e08 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -1,6 +1,6 @@
 use crate::bstr::ByteStr;
 use crate::ffi::OsStr;
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
 use crate::os::net::linux_ext;
 use crate::os::unix::ffi::OsStrExt;
 use crate::path::Path;
@@ -241,7 +241,7 @@ impl SocketAddr {
 
         // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
         if len == 0
-            || (cfg!(not(any(target_os = "linux", target_os = "android")))
+            || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
                 && self.addr.sun_path[0] == 0)
         {
             AddressKind::Unnamed
@@ -256,8 +256,8 @@ impl SocketAddr {
 #[stable(feature = "unix_socket_abstract", since = "1.70.0")]
 impl Sealed for SocketAddr {}
 
-#[doc(cfg(any(target_os = "android", target_os = "linux")))]
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin")))]
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[stable(feature = "unix_socket_abstract", since = "1.70.0")]
 impl linux_ext::addr::SocketAddrExt for SocketAddr {
     fn as_abstract_name(&self) -> Option<&[u8]> {
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 36967fc3f98..d0984bdfb99 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -16,7 +16,8 @@ use crate::sys::net::Socket;
     not(target_os = "linux"),
     not(target_os = "android"),
     not(target_os = "netbsd"),
-    not(target_os = "freebsd")
+    not(target_os = "freebsd"),
+    not(target_os = "cygwin"),
 ))]
 #[allow(non_camel_case_types)]
 mod libc {
@@ -195,14 +196,15 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
     not(target_os = "android"),
     not(target_os = "linux"),
     not(target_os = "netbsd"),
-    not(target_os = "freebsd")
+    not(target_os = "freebsd"),
+    not(target_os = "cygwin"),
 ))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 #[derive(Clone)]
 pub struct SocketCred(());
 
 /// Unix credential.
-#[cfg(any(target_os = "android", target_os = "linux",))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 #[derive(Clone)]
 pub struct SocketCred(libc::ucred);
@@ -217,8 +219,8 @@ pub struct SocketCred(libc::sockcred);
 #[derive(Clone)]
 pub struct SocketCred(libc::sockcred2);
 
-#[doc(cfg(any(target_os = "android", target_os = "linux")))]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin")))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 impl SocketCred {
     /// Creates a Unix credential struct.
     ///
@@ -407,7 +409,8 @@ impl<'a> Iterator for ScmRights<'a> {
     not(target_os = "android"),
     not(target_os = "linux"),
     not(target_os = "netbsd"),
-    not(target_os = "freebsd")
+    not(target_os = "freebsd"),
+    not(target_os = "cygwin"),
 ))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
@@ -415,7 +418,7 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
 /// This control message contains unix credentials.
 ///
 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
-#[cfg(any(target_os = "android", target_os = "linux",))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
 
@@ -432,7 +435,8 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
     target_os = "android",
     target_os = "linux",
     target_os = "netbsd",
-    target_os = "freebsd"
+    target_os = "freebsd",
+    target_os = "cygwin",
 ))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 impl<'a> Iterator for ScmCredentials<'a> {
@@ -460,7 +464,8 @@ pub enum AncillaryData<'a> {
         target_os = "android",
         target_os = "linux",
         target_os = "netbsd",
-        target_os = "freebsd"
+        target_os = "freebsd",
+        target_os = "cygwin",
     ))]
     ScmCredentials(ScmCredentials<'a>),
 }
@@ -489,7 +494,8 @@ impl<'a> AncillaryData<'a> {
         target_os = "android",
         target_os = "linux",
         target_os = "netbsd",
-        target_os = "freebsd"
+        target_os = "freebsd",
+        target_os = "cygwin",
     ))]
     unsafe fn as_credentials(data: &'a [u8]) -> Self {
         let ancillary_data_iter = AncillaryDataIter::new(data);
@@ -507,7 +513,7 @@ impl<'a> AncillaryData<'a> {
             match (*cmsg).cmsg_level {
                 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
                     libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
-                    #[cfg(any(target_os = "android", target_os = "linux",))]
+                    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
                     libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
                     #[cfg(target_os = "freebsd")]
                     libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
@@ -729,7 +735,8 @@ impl<'a> SocketAncillary<'a> {
         target_os = "android",
         target_os = "linux",
         target_os = "netbsd",
-        target_os = "freebsd"
+        target_os = "freebsd",
+        target_os = "cygwin",
     ))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index 7735637c840..469bfbb0d83 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -14,9 +14,9 @@
 use libc::MSG_NOSIGNAL;
 
 use super::{SocketAddr, sockaddr_un};
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
 use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to};
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
 use crate::io::{IoSlice, IoSliceMut};
 use crate::net::Shutdown;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
@@ -397,8 +397,14 @@ impl UnixDatagram {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(target_os = "android", target_os = "linux", target_os = "cygwin"),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
     /// use std::io::IoSliceMut;
@@ -428,7 +434,7 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn recv_vectored_with_ancillary_from(
         &self,
@@ -447,8 +453,14 @@ impl UnixDatagram {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(target_os = "android", target_os = "linux", target_os = "cygwin"),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
     /// use std::io::IoSliceMut;
@@ -478,7 +490,7 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn recv_vectored_with_ancillary(
         &self,
@@ -588,8 +600,14 @@ impl UnixDatagram {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(target_os = "android", target_os = "linux", target_os = "cygwin"),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
     /// use std::io::IoSlice;
@@ -613,7 +631,7 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
         &self,
@@ -630,8 +648,14 @@ impl UnixDatagram {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(target_os = "android", target_os = "linux", target_os = "cygwin"),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
     /// use std::io::IoSlice;
@@ -655,7 +679,7 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn send_vectored_with_ancillary(
         &self,
diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs
index 6cd62303a53..94523d7d1e4 100644
--- a/library/std/src/os/unix/net/mod.rs
+++ b/library/std/src/os/unix/net/mod.rs
@@ -4,8 +4,8 @@
 #![stable(feature = "unix_socket", since = "1.10.0")]
 
 mod addr;
-#[doc(cfg(any(target_os = "android", target_os = "linux")))]
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin")))]
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
 mod ancillary;
 mod datagram;
 mod listener;
@@ -27,7 +27,7 @@ mod ucred;
 
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub use self::addr::*;
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub use self::ancillary::*;
 #[stable(feature = "unix_socket", since = "1.10.0")]
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 768fa77a5f8..ea4171a7d28 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -16,7 +16,7 @@ cfg_select! {
 }
 
 use super::{SocketAddr, sockaddr_un};
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
 use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to};
 #[cfg(any(
     target_os = "android",
@@ -508,8 +508,14 @@ impl UnixStream {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(target_os = "android", target_os = "linux", target_os = "cygwin"),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
     /// use std::io::IoSliceMut;
@@ -539,7 +545,7 @@ impl UnixStream {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn recv_vectored_with_ancillary(
         &self,
@@ -557,8 +563,14 @@ impl UnixStream {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(target_os = "android", target_os = "linux", target_os = "cygwin"),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixStream, SocketAncillary};
     /// use std::io::IoSlice;
@@ -582,7 +594,7 @@ impl UnixStream {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn send_vectored_with_ancillary(
         &self,
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index 9a88687b1df..4666b5e3c6c 100644
--- a/library/std/src/os/unix/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
@@ -3,6 +3,8 @@ use crate::io::prelude::*;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
 #[cfg(target_os = "android")]
 use crate::os::android::net::{SocketAddrExt, UnixSocketExt};
+#[cfg(target_os = "cygwin")]
+use crate::os::cygwin::net::{SocketAddrExt, UnixSocketExt};
 #[cfg(target_os = "linux")]
 use crate::os::linux::net::{SocketAddrExt, UnixSocketExt};
 #[cfg(any(target_os = "android", target_os = "linux"))]
@@ -170,6 +172,7 @@ fn long_path() {
 #[test]
 #[cfg(not(target_os = "nto"))]
 #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake
 fn timeouts() {
     let dir = tmpdir();
     let socket_path = dir.path().join("sock");
@@ -198,6 +201,7 @@ fn timeouts() {
 
 #[test]
 #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake
 fn test_read_timeout() {
     let dir = tmpdir();
     let socket_path = dir.path().join("sock");
@@ -218,6 +222,7 @@ fn test_read_timeout() {
 
 #[test]
 #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake
 fn test_read_with_timeout() {
     let dir = tmpdir();
     let socket_path = dir.path().join("sock");
@@ -246,6 +251,7 @@ fn test_read_with_timeout() {
 // when passed zero Durations
 #[test]
 #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake
 fn test_unix_stream_timeout_zero_duration() {
     let dir = tmpdir();
     let socket_path = dir.path().join("sock");
@@ -283,6 +289,7 @@ fn test_unix_datagram() {
 
 #[test]
 #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin autobinds an address
 fn test_unnamed_unix_datagram() {
     let dir = tmpdir();
     let path1 = dir.path().join("sock1");
@@ -326,6 +333,7 @@ fn test_unix_datagram_connect_to_recv_addr() {
 
 #[test]
 #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin autobinds an address
 fn test_connect_unix_datagram() {
     let dir = tmpdir();
     let path1 = dir.path().join("sock1");
@@ -425,8 +433,9 @@ fn abstract_namespace_not_allowed_connect() {
     assert!(UnixStream::connect("\0asdf").is_err());
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[test]
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin cannot bind to abstract addr
 fn test_abstract_stream_connect() {
     let msg1 = b"hello";
     let msg2 = b"world";
@@ -456,8 +465,9 @@ fn test_abstract_stream_connect() {
     thread.join().unwrap();
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[test]
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin cannot bind to abstract addr
 fn test_abstract_stream_iter() {
     let addr = or_panic!(SocketAddr::from_abstract_name(b"hidden"));
     let listener = or_panic!(UnixListener::bind_addr(&addr));
@@ -478,8 +488,9 @@ fn test_abstract_stream_iter() {
     thread.join().unwrap();
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[test]
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin cannot bind to abstract addr
 fn test_abstract_datagram_bind_send_to_addr() {
     let addr1 = or_panic!(SocketAddr::from_abstract_name(b"ns1"));
     let sock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
@@ -499,8 +510,9 @@ fn test_abstract_datagram_bind_send_to_addr() {
     assert_eq!(addr.as_abstract_name().unwrap(), b"ns1");
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[test]
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin cannot bind to abstract addr
 fn test_abstract_datagram_connect_addr() {
     let addr1 = or_panic!(SocketAddr::from_abstract_name(b"ns3"));
     let bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
@@ -524,7 +536,7 @@ fn test_abstract_datagram_connect_addr() {
     or_panic!(bsock2.recv_from(&mut buf));
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[test]
 fn test_abstract_name_too_long() {
     match SocketAddr::from_abstract_name(
@@ -538,7 +550,7 @@ fn test_abstract_name_too_long() {
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[test]
 fn test_abstract_no_pathname_and_not_unnamed() {
     let name = b"local";
@@ -669,9 +681,10 @@ fn test_send_vectored_fds_unix_stream() {
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
 #[test]
 #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
+#[cfg_attr(target_os = "cygwin", ignore)] // Cygwin recvmsg doesn't support Unix sockets
 fn test_send_vectored_with_ancillary_to_unix_datagram() {
     fn getpid() -> libc::pid_t {
         unsafe { libc::getpid() }
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index ddb8dbd8fee..b445f368aeb 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -5,6 +5,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::fs::{self, Metadata, OpenOptions};
+use crate::io::BorrowedCursor;
 use crate::path::Path;
 use crate::sealed::Sealed;
 use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
@@ -49,6 +50,44 @@ pub trait FileExt {
     #[stable(feature = "file_offset", since = "1.15.0")]
     fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
 
+    /// Seeks to a given position and reads some bytes into the buffer.
+    ///
+    /// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except that it is passed
+    /// a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The
+    /// new data will be appended to any existing contents of `buf`.
+    ///
+    /// Reading beyond the end of the file will always succeed without reading any bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(core_io_borrowed_buf)]
+    /// #![feature(read_buf_at)]
+    ///
+    /// use std::io;
+    /// use std::io::BorrowedBuf;
+    /// use std::fs::File;
+    /// use std::mem::MaybeUninit;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("pi.txt")?;
+    ///
+    ///     // Read some bytes starting from offset 2
+    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
+    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    ///     file.seek_read_buf(buf.unfilled(), 2)?;
+    ///
+    ///     assert!(buf.filled().starts_with(b"1"));
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "read_buf_at", issue = "140771")]
+    fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        io::default_read_buf(|b| self.seek_read(b, offset), buf)
+    }
+
     /// Seeks to a given position and writes a number of bytes.
     ///
     /// Returns the number of bytes written.
@@ -89,6 +128,10 @@ impl FileExt for fs::File {
         self.as_inner().read_at(buf, offset)
     }
 
+    fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.as_inner().read_buf_at(buf, offset)
+    }
+
     fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         self.as_inner().write_at(buf, offset)
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 5ccea1c972c..70ba502d684 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1575,8 +1575,6 @@ impl PathBuf {
     /// # Examples
     ///
     /// ```
-    /// #![feature(path_add_extension)]
-    ///
     /// use std::path::{Path, PathBuf};
     ///
     /// let mut p = PathBuf::from("/feel/the");
@@ -1596,7 +1594,7 @@ impl PathBuf {
     /// p.add_extension("");
     /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
     /// ```
-    #[unstable(feature = "path_add_extension", issue = "127292")]
+    #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")]
     pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
         self._add_extension(extension.as_ref())
     }
@@ -2109,7 +2107,7 @@ impl PartialEq for PathBuf {
 impl cmp::PartialEq<str> for PathBuf {
     #[inline]
     fn eq(&self, other: &str) -> bool {
-        &*self == other
+        Path::eq(self, other)
     }
 }
 
@@ -2880,8 +2878,6 @@ impl Path {
     /// # Examples
     ///
     /// ```
-    /// #![feature(path_add_extension)]
-    ///
     /// use std::path::{Path, PathBuf};
     ///
     /// let path = Path::new("foo.rs");
@@ -2892,7 +2888,7 @@ impl Path {
     /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
     /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
     /// ```
-    #[unstable(feature = "path_add_extension", issue = "127292")]
+    #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")]
     pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
         let mut new_path = self.to_path_buf();
         new_path.add_extension(extension);
@@ -3041,6 +3037,14 @@ impl Path {
     ///
     /// This is an alias to [`fs::canonicalize`].
     ///
+    /// # Errors
+    ///
+    /// This method will return an error in the following situations, but is not
+    /// limited to just these cases:
+    ///
+    /// * `path` does not exist.
+    /// * A non-final component in path is not a directory.
+    ///
     /// # Examples
     ///
     /// ```no_run
diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs
index a12f692e754..2b2dfe48e89 100644
--- a/library/std/src/sys/fd/unix.rs
+++ b/library/std/src/sys/fd/unix.rs
@@ -18,6 +18,21 @@ use libc::off_t as off64_t;
 ))]
 use libc::off64_t;
 
+cfg_select! {
+    any(
+        all(target_os = "linux", not(target_env = "musl")),
+        target_os = "android",
+        target_os = "hurd",
+    ) => {
+        // Prefer explicit pread64 for 64-bit offset independently of libc
+        // #[cfg(gnu_file_offset_bits64)].
+        use libc::pread64;
+    }
+    _ => {
+        use libc::pread as pread64;
+    }
+}
+
 use crate::cmp;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
@@ -146,42 +161,47 @@ impl FileDesc {
         (&mut me).read_to_end(buf)
     }
 
-    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        #[cfg(not(any(
-            all(target_os = "linux", not(target_env = "musl")),
-            target_os = "android",
-            target_os = "hurd"
-        )))]
-        use libc::pread as pread64;
-        #[cfg(any(
-            all(target_os = "linux", not(target_env = "musl")),
-            target_os = "android",
-            target_os = "hurd"
-        ))]
-        use libc::pread64;
-
-        unsafe {
-            cvt(pread64(
+        cvt(unsafe {
+            pread64(
                 self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut libc::c_void,
                 cmp::min(buf.len(), READ_LIMIT),
-                offset as off64_t,
-            ))
-            .map(|n| n as usize)
-        }
+                offset as off64_t, // EINVAL if offset + count overflows
+            )
+        })
+        .map(|n| n as usize)
     }
 
     pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
         let ret = cvt(unsafe {
             libc::read(
                 self.as_raw_fd(),
-                cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
+                cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
+                cmp::min(cursor.capacity(), READ_LIMIT),
+            )
+        })?;
+
+        // SAFETY: `ret` bytes were written to the initialized portion of the buffer
+        unsafe {
+            cursor.advance_unchecked(ret as usize);
+        }
+        Ok(())
+    }
+
+    pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
+        let ret = cvt(unsafe {
+            pread64(
+                self.as_raw_fd(),
+                cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
                 cmp::min(cursor.capacity(), READ_LIMIT),
+                offset as off64_t, // EINVAL if offset + count overflows
             )
         })?;
 
-        // Safety: `ret` bytes were written to the initialized portion of the buffer
+        // SAFETY: `ret` bytes were written to the initialized portion of the buffer
         unsafe {
             cursor.advance_unchecked(ret as usize);
         }
@@ -369,7 +389,6 @@ impl FileDesc {
         )))
     }
 
-    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         #[cfg(not(any(
             all(target_os = "linux", not(target_env = "musl")),
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index a89c3bbacfb..dfd6ce56a76 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -1293,6 +1293,15 @@ impl File {
         return Ok(());
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn lock(&self) -> io::Result<()> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_WRLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
+        Ok(())
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
@@ -1300,6 +1309,7 @@ impl File {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn lock(&self) -> io::Result<()> {
@@ -1320,6 +1330,15 @@ impl File {
         return Ok(());
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn lock_shared(&self) -> io::Result<()> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_RDLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
+        Ok(())
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
@@ -1327,6 +1346,7 @@ impl File {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn lock_shared(&self) -> io::Result<()> {
@@ -1355,6 +1375,23 @@ impl File {
         }
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn try_lock(&self) -> Result<(), TryLockError> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_WRLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
+        if let Err(err) = result {
+            if err.kind() == io::ErrorKind::WouldBlock {
+                Err(TryLockError::WouldBlock)
+            } else {
+                Err(TryLockError::Error(err))
+            }
+        } else {
+            Ok(())
+        }
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
@@ -1362,6 +1399,7 @@ impl File {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
@@ -1393,6 +1431,23 @@ impl File {
         }
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_RDLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
+        if let Err(err) = result {
+            if err.kind() == io::ErrorKind::WouldBlock {
+                Err(TryLockError::WouldBlock)
+            } else {
+                Err(TryLockError::Error(err))
+            }
+        } else {
+            Ok(())
+        }
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
@@ -1400,6 +1455,7 @@ impl File {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@@ -1423,6 +1479,15 @@ impl File {
         return Ok(());
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn unlock(&self) -> io::Result<()> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_UNLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
+        Ok(())
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
@@ -1430,6 +1495,7 @@ impl File {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn unlock(&self) -> io::Result<()> {
@@ -1463,6 +1529,10 @@ impl File {
         self.0.read_buf(cursor)
     }
 
+    pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.0.read_buf_at(cursor, offset)
+    }
+
     pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
         self.0.read_vectored_at(bufs, offset)
     }
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index bac278f7c8f..ccfe410627f 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -605,6 +605,10 @@ impl File {
         self.handle.read_buf(cursor)
     }
 
+    pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.handle.read_buf_at(cursor, offset)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.handle.write(buf)
     }
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 6324c1a232a..8c115015580 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -26,6 +26,7 @@ pub mod io;
 pub mod net;
 pub mod os_str;
 pub mod path;
+pub mod platform_version;
 pub mod process;
 pub mod random;
 pub mod stdio;
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index 8b5970d1494..8216f8d2fd5 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -361,7 +361,7 @@ impl Socket {
         self.recv_from_with_flags(buf, 0)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
         let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?;
         Ok(n as usize)
@@ -384,7 +384,7 @@ impl Socket {
         self.0.is_write_vectored()
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
         let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?;
         Ok(n as usize)
@@ -472,12 +472,12 @@ impl Socket {
         Ok(raw != 0)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn set_quickack(&self, quickack: bool) -> io::Result<()> {
         setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn quickack(&self) -> io::Result<bool> {
         let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)?;
         Ok(raw != 0)
@@ -541,12 +541,12 @@ impl Socket {
         Ok(raw != 0)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
         setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn passcred(&self) -> io::Result<bool> {
         let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?;
         Ok(passcred != 0)
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index 82a880faf5f..76c8aa939d3 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -136,6 +136,19 @@ impl Handle {
         }
     }
 
+    pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
+        let read = unsafe {
+            self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset))
+        }?;
+
+        // SAFETY: `read` bytes were written to the initialized portion of the buffer
+        unsafe {
+            cursor.advance_unchecked(read);
+        }
+        Ok(())
+    }
+
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let mut me = self;
 
diff --git a/library/std/src/sys/platform_version/darwin/core_foundation.rs b/library/std/src/sys/platform_version/darwin/core_foundation.rs
new file mode 100644
index 00000000000..1e0d15fcf66
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/core_foundation.rs
@@ -0,0 +1,180 @@
+//! Minimal utilities for interfacing with a dynamically loaded CoreFoundation.
+#![allow(non_snake_case, non_upper_case_globals)]
+use super::root_relative;
+use crate::ffi::{CStr, c_char, c_void};
+use crate::ptr::null_mut;
+use crate::sys::common::small_c_string::run_path_with_cstr;
+
+// MacTypes.h
+pub(super) type Boolean = u8;
+// CoreFoundation/CFBase.h
+pub(super) type CFTypeID = usize;
+pub(super) type CFOptionFlags = usize;
+pub(super) type CFIndex = isize;
+pub(super) type CFTypeRef = *mut c_void;
+pub(super) type CFAllocatorRef = CFTypeRef;
+pub(super) const kCFAllocatorDefault: CFAllocatorRef = null_mut();
+// CoreFoundation/CFError.h
+pub(super) type CFErrorRef = CFTypeRef;
+// CoreFoundation/CFData.h
+pub(super) type CFDataRef = CFTypeRef;
+// CoreFoundation/CFPropertyList.h
+pub(super) const kCFPropertyListImmutable: CFOptionFlags = 0;
+pub(super) type CFPropertyListFormat = CFIndex;
+pub(super) type CFPropertyListRef = CFTypeRef;
+// CoreFoundation/CFString.h
+pub(super) type CFStringRef = CFTypeRef;
+pub(super) type CFStringEncoding = u32;
+pub(super) const kCFStringEncodingUTF8: CFStringEncoding = 0x08000100;
+// CoreFoundation/CFDictionary.h
+pub(super) type CFDictionaryRef = CFTypeRef;
+
+/// An open handle to the dynamically loaded CoreFoundation framework.
+///
+/// This is `dlopen`ed, and later `dlclose`d. This is done to try to avoid
+/// "leaking" the CoreFoundation symbols to the rest of the user's binary if
+/// they decided to not link CoreFoundation themselves.
+///
+/// It is also faster to look up symbols directly via this handle than with
+/// `RTLD_DEFAULT`.
+pub(super) struct CFHandle(*mut c_void);
+
+macro_rules! dlsym_fn {
+    (
+        unsafe fn $name:ident($($param:ident: $param_ty:ty),* $(,)?) $(-> $ret:ty)?;
+    ) => {
+        pub(super) unsafe fn $name(&self, $($param: $param_ty),*) $(-> $ret)? {
+            let ptr = unsafe {
+                libc::dlsym(
+                    self.0,
+                    concat!(stringify!($name), '\0').as_bytes().as_ptr().cast(),
+                )
+            };
+            if ptr.is_null() {
+                let err = unsafe { CStr::from_ptr(libc::dlerror()) };
+                panic!("could not find function {}: {err:?}", stringify!($name));
+            }
+
+            // SAFETY: Just checked that the symbol isn't NULL, and macro invoker verifies that
+            // the signature is correct.
+            let fnptr = unsafe {
+                crate::mem::transmute::<
+                    *mut c_void,
+                    unsafe extern "C" fn($($param_ty),*) $(-> $ret)?,
+                >(ptr)
+            };
+
+            // SAFETY: Upheld by caller.
+            unsafe { fnptr($($param),*) }
+        }
+    };
+}
+
+impl CFHandle {
+    /// Link to the CoreFoundation dylib, and look up symbols from that.
+    pub(super) fn new() -> Self {
+        // We explicitly use non-versioned path here, to allow this to work on older iOS devices.
+        let cf_path =
+            root_relative("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation");
+
+        let handle = run_path_with_cstr(&cf_path, &|path| unsafe {
+            Ok(libc::dlopen(path.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL))
+        })
+        .expect("failed allocating string");
+
+        if handle.is_null() {
+            let err = unsafe { CStr::from_ptr(libc::dlerror()) };
+            panic!("could not open CoreFoundation.framework: {err:?}");
+        }
+
+        Self(handle)
+    }
+
+    pub(super) fn kCFAllocatorNull(&self) -> CFAllocatorRef {
+        // Available: in all CF versions.
+        let static_ptr = unsafe { libc::dlsym(self.0, c"kCFAllocatorNull".as_ptr()) };
+        if static_ptr.is_null() {
+            let err = unsafe { CStr::from_ptr(libc::dlerror()) };
+            panic!("could not find kCFAllocatorNull: {err:?}");
+        }
+        unsafe { *static_ptr.cast() }
+    }
+
+    // CoreFoundation/CFBase.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFRelease(cf: CFTypeRef);
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID;
+    );
+
+    // CoreFoundation/CFData.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFDataCreateWithBytesNoCopy(
+            allocator: CFAllocatorRef,
+            bytes: *const u8,
+            length: CFIndex,
+            bytes_deallocator: CFAllocatorRef,
+        ) -> CFDataRef;
+    );
+
+    // CoreFoundation/CFPropertyList.h
+    dlsym_fn!(
+        // Available: since macOS 10.6.
+        unsafe fn CFPropertyListCreateWithData(
+            allocator: CFAllocatorRef,
+            data: CFDataRef,
+            options: CFOptionFlags,
+            format: *mut CFPropertyListFormat,
+            error: *mut CFErrorRef,
+        ) -> CFPropertyListRef;
+    );
+
+    // CoreFoundation/CFString.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFStringGetTypeID() -> CFTypeID;
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFStringCreateWithCStringNoCopy(
+            alloc: CFAllocatorRef,
+            c_str: *const c_char,
+            encoding: CFStringEncoding,
+            contents_deallocator: CFAllocatorRef,
+        ) -> CFStringRef;
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFStringGetCString(
+            the_string: CFStringRef,
+            buffer: *mut c_char,
+            buffer_size: CFIndex,
+            encoding: CFStringEncoding,
+        ) -> Boolean;
+    );
+
+    // CoreFoundation/CFDictionary.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFDictionaryGetTypeID() -> CFTypeID;
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFDictionaryGetValue(
+            the_dict: CFDictionaryRef,
+            key: *const c_void,
+        ) -> *const c_void;
+    );
+}
+
+impl Drop for CFHandle {
+    fn drop(&mut self) {
+        // Ignore errors when closing. This is also what `libloading` does:
+        // https://docs.rs/libloading/0.8.6/src/libloading/os/unix/mod.rs.html#374
+        let _ = unsafe { libc::dlclose(self.0) };
+    }
+}
diff --git a/library/std/src/sys/platform_version/darwin/mod.rs b/library/std/src/sys/platform_version/darwin/mod.rs
new file mode 100644
index 00000000000..06b97fcdef4
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/mod.rs
@@ -0,0 +1,351 @@
+use self::core_foundation::{
+    CFDictionaryRef, CFHandle, CFIndex, CFStringRef, CFTypeRef, kCFAllocatorDefault,
+    kCFPropertyListImmutable, kCFStringEncodingUTF8,
+};
+use crate::borrow::Cow;
+use crate::bstr::ByteStr;
+use crate::ffi::{CStr, c_char};
+use crate::num::{NonZero, ParseIntError};
+use crate::path::{Path, PathBuf};
+use crate::ptr::null_mut;
+use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::{env, fs};
+
+mod core_foundation;
+mod public_extern;
+#[cfg(test)]
+mod tests;
+
+/// The version of the operating system.
+///
+/// We use a packed u32 here to allow for fast comparisons and to match Mach-O's `LC_BUILD_VERSION`.
+type OSVersion = u32;
+
+/// Combine parts of a version into an [`OSVersion`].
+///
+/// The size of the parts are inherently limited by Mach-O's `LC_BUILD_VERSION`.
+#[inline]
+const fn pack_os_version(major: u16, minor: u8, patch: u8) -> OSVersion {
+    let (major, minor, patch) = (major as u32, minor as u32, patch as u32);
+    (major << 16) | (minor << 8) | patch
+}
+
+/// [`pack_os_version`], but takes `i32` and saturates.
+///
+/// Instead of using e.g. `major as u16`, which truncates.
+#[inline]
+fn pack_i32_os_version(major: i32, minor: i32, patch: i32) -> OSVersion {
+    let major: u16 = major.try_into().unwrap_or(u16::MAX);
+    let minor: u8 = minor.try_into().unwrap_or(u8::MAX);
+    let patch: u8 = patch.try_into().unwrap_or(u8::MAX);
+    pack_os_version(major, minor, patch)
+}
+
+/// Get the current OS version, packed according to [`pack_os_version`].
+///
+/// # Semantics
+///
+/// The reported version on macOS might be 10.16 if the SDK version of the binary is less than 11.0.
+/// This is a workaround that Apple implemented to handle applications that assumed that macOS
+/// versions would always start with "10", see:
+/// <https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.81.4/libsyscall/wrappers/system-version-compat.c>
+///
+/// It _is_ possible to get the real version regardless of the SDK version of the binary, this is
+/// what Zig does:
+/// <https://github.com/ziglang/zig/blob/0.13.0/lib/std/zig/system/darwin/macos.zig>
+///
+/// We choose to not do that, and instead follow Apple's behaviour here, and return 10.16 when
+/// compiled with an older SDK; the user should instead upgrade their tooling.
+///
+/// NOTE: `rustc` currently doesn't set the right SDK version when linking with ld64, so this will
+/// have the wrong behaviour with `-Clinker=ld` on x86_64. But that's a `rustc` bug:
+/// <https://github.com/rust-lang/rust/issues/129432>
+#[inline]
+fn current_version() -> OSVersion {
+    // Cache the lookup for performance.
+    //
+    // 0.0.0 is never going to be a valid version ("vtool" reports "n/a" on 0 versions), so we use
+    // that as our sentinel value.
+    static CURRENT_VERSION: AtomicU32 = AtomicU32::new(0);
+
+    // We use relaxed atomics instead of e.g. a `Once`, it doesn't matter if multiple threads end up
+    // racing to read or write the version, `lookup_version` should be idempotent and always return
+    // the same value.
+    //
+    // `compiler-rt` uses `dispatch_once`, but that's overkill for the reasons above.
+    let version = CURRENT_VERSION.load(Ordering::Relaxed);
+    if version == 0 {
+        let version = lookup_version().get();
+        CURRENT_VERSION.store(version, Ordering::Relaxed);
+        version
+    } else {
+        version
+    }
+}
+
+/// Look up the os version.
+///
+/// # Aborts
+///
+/// Aborts if reading or parsing the version fails (or if the system was out of memory).
+///
+/// We deliberately choose to abort, as having this silently return an invalid OS version would be
+/// impossible for a user to debug.
+// The lookup is costly and should be on the cold path because of the cache in `current_version`.
+#[cold]
+// Micro-optimization: We use `extern "C"` to abort on panic, allowing `current_version` (inlined)
+// to be free of unwind handling. Aborting is required for `__isPlatformVersionAtLeast` anyhow.
+extern "C" fn lookup_version() -> NonZero<OSVersion> {
+    // Try to read from `sysctl` first (faster), but if that fails, fall back to reading the
+    // property list (this is roughly what `_availability_version_check` does internally).
+    let version = version_from_sysctl().unwrap_or_else(version_from_plist);
+
+    // Use `NonZero` to try to make it clearer to the optimizer that this will never return 0.
+    NonZero::new(version).expect("version cannot be 0.0.0")
+}
+
+/// Read the version from `kern.osproductversion` or `kern.iossupportversion`.
+///
+/// This is faster than `version_from_plist`, since it doesn't need to invoke `dlsym`.
+fn version_from_sysctl() -> Option<OSVersion> {
+    // This won't work in the simulator, as `kern.osproductversion` returns the host macOS version,
+    // and `kern.iossupportversion` returns the host macOS' iOSSupportVersion (while you can run
+    // simulators with many different iOS versions).
+    if cfg!(target_abi = "sim") {
+        // Fall back to `version_from_plist` on these targets.
+        return None;
+    }
+
+    let sysctl_version = |name: &CStr| {
+        let mut buf: [u8; 32] = [0; 32];
+        let mut size = buf.len();
+        let ptr = buf.as_mut_ptr().cast();
+        let ret = unsafe { libc::sysctlbyname(name.as_ptr(), ptr, &mut size, null_mut(), 0) };
+        if ret != 0 {
+            // This sysctl is not available.
+            return None;
+        }
+        let buf = &buf[..(size - 1)];
+
+        if buf.is_empty() {
+            // The buffer may be empty when using `kern.iossupportversion` on an actual iOS device,
+            // or on visionOS when running under "Designed for iPad".
+            //
+            // In that case, fall back to `kern.osproductversion`.
+            return None;
+        }
+
+        Some(parse_os_version(buf).unwrap_or_else(|err| {
+            panic!("failed parsing version from sysctl ({}): {err}", ByteStr::new(buf))
+        }))
+    };
+
+    // When `target_os = "ios"`, we may be in many different states:
+    // - Native iOS device.
+    // - iOS Simulator.
+    // - Mac Catalyst.
+    // - Mac + "Designed for iPad".
+    // - Native visionOS device + "Designed for iPad".
+    // - visionOS simulator + "Designed for iPad".
+    //
+    // Of these, only native, Mac Catalyst and simulators can be differentiated at compile-time
+    // (with `target_abi = ""`, `target_abi = "macabi"` and `target_abi = "sim"` respectively).
+    //
+    // That is, "Designed for iPad" will act as iOS at compile-time, but the `ProductVersion` will
+    // still be the host macOS or visionOS version.
+    //
+    // Furthermore, we can't even reliably differentiate between these at runtime, since
+    // `dyld_get_active_platform` isn't publicly available.
+    //
+    // Fortunately, we won't need to know any of that; we can simply attempt to get the
+    // `iOSSupportVersion` (which may be set on native iOS too, but then it will be set to the host
+    // iOS version), and if that fails, fall back to the `ProductVersion`.
+    if cfg!(target_os = "ios") {
+        // https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.81.4/bsd/kern/kern_sysctl.c#L2077-L2100
+        if let Some(ios_support_version) = sysctl_version(c"kern.iossupportversion") {
+            return Some(ios_support_version);
+        }
+
+        // On Mac Catalyst, if we failed looking up `iOSSupportVersion`, we don't want to
+        // accidentally fall back to `ProductVersion`.
+        if cfg!(target_abi = "macabi") {
+            return None;
+        }
+    }
+
+    // Introduced in macOS 10.13.4.
+    // https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.81.4/bsd/kern/kern_sysctl.c#L2015-L2051
+    sysctl_version(c"kern.osproductversion")
+}
+
+/// Look up the current OS version(s) from `/System/Library/CoreServices/SystemVersion.plist`.
+///
+/// More specifically, from the `ProductVersion` and `iOSSupportVersion` keys, and from
+/// `$IPHONE_SIMULATOR_ROOT/System/Library/CoreServices/SystemVersion.plist` on the simulator.
+///
+/// This file was introduced in macOS 10.3, which is well below the minimum supported version by
+/// `rustc`, which is (at the time of writing) macOS 10.12.
+///
+/// # Implementation
+///
+/// We do roughly the same thing in here as `compiler-rt`, and dynamically look up CoreFoundation
+/// utilities for parsing PLists (to avoid having to re-implement that in here, as pulling in a full
+/// PList parser into `std` seems costly).
+///
+/// If this is found to be undesirable, we _could_ possibly hack it by parsing the PList manually
+/// (it seems to use the plain-text "xml1" encoding/format in all versions), but that seems brittle.
+fn version_from_plist() -> OSVersion {
+    // Read `SystemVersion.plist`. Always present on Apple platforms, reading it cannot fail.
+    let path = root_relative("/System/Library/CoreServices/SystemVersion.plist");
+    let plist_buffer = fs::read(&path).unwrap_or_else(|e| panic!("failed reading {path:?}: {e}"));
+    let cf_handle = CFHandle::new();
+    parse_version_from_plist(&cf_handle, &plist_buffer)
+}
+
+/// Parse OS version from the given PList.
+///
+/// Split out from [`version_from_plist`] to allow for testing.
+fn parse_version_from_plist(cf_handle: &CFHandle, plist_buffer: &[u8]) -> OSVersion {
+    let plist_data = unsafe {
+        cf_handle.CFDataCreateWithBytesNoCopy(
+            kCFAllocatorDefault,
+            plist_buffer.as_ptr(),
+            plist_buffer.len() as CFIndex,
+            cf_handle.kCFAllocatorNull(),
+        )
+    };
+    assert!(!plist_data.is_null(), "failed creating CFData");
+    let _plist_data_release = Deferred(|| unsafe { cf_handle.CFRelease(plist_data) });
+
+    let plist = unsafe {
+        cf_handle.CFPropertyListCreateWithData(
+            kCFAllocatorDefault,
+            plist_data,
+            kCFPropertyListImmutable,
+            null_mut(), // Don't care about the format of the PList.
+            null_mut(), // Don't care about the error data.
+        )
+    };
+    assert!(!plist.is_null(), "failed reading PList in SystemVersion.plist");
+    let _plist_release = Deferred(|| unsafe { cf_handle.CFRelease(plist) });
+
+    assert_eq!(
+        unsafe { cf_handle.CFGetTypeID(plist) },
+        unsafe { cf_handle.CFDictionaryGetTypeID() },
+        "SystemVersion.plist did not contain a dictionary at the top level"
+    );
+    let plist: CFDictionaryRef = plist.cast();
+
+    // Same logic as in `version_from_sysctl`.
+    if cfg!(target_os = "ios") {
+        if let Some(ios_support_version) =
+            unsafe { string_version_key(cf_handle, plist, c"iOSSupportVersion") }
+        {
+            return ios_support_version;
+        }
+
+        // Force Mac Catalyst to use iOSSupportVersion (do not fall back to ProductVersion).
+        if cfg!(target_abi = "macabi") {
+            panic!("expected iOSSupportVersion in SystemVersion.plist");
+        }
+    }
+
+    // On all other platforms, we can find the OS version by simply looking at `ProductVersion`.
+    unsafe { string_version_key(cf_handle, plist, c"ProductVersion") }
+        .expect("expected ProductVersion in SystemVersion.plist")
+}
+
+/// Look up a string key in a CFDictionary, and convert it to an [`OSVersion`].
+unsafe fn string_version_key(
+    cf_handle: &CFHandle,
+    plist: CFDictionaryRef,
+    lookup_key: &CStr,
+) -> Option<OSVersion> {
+    let cf_lookup_key = unsafe {
+        cf_handle.CFStringCreateWithCStringNoCopy(
+            kCFAllocatorDefault,
+            lookup_key.as_ptr(),
+            kCFStringEncodingUTF8,
+            cf_handle.kCFAllocatorNull(),
+        )
+    };
+    assert!(!cf_lookup_key.is_null(), "failed creating CFString");
+    let _lookup_key_release = Deferred(|| unsafe { cf_handle.CFRelease(cf_lookup_key) });
+
+    let value: CFTypeRef =
+        unsafe { cf_handle.CFDictionaryGetValue(plist, cf_lookup_key) }.cast_mut();
+    // `CFDictionaryGetValue` is a "getter", so we should not release,
+    // the value is held alive internally by the CFDictionary, see:
+    // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW12
+    if value.is_null() {
+        return None;
+    }
+
+    assert_eq!(
+        unsafe { cf_handle.CFGetTypeID(value) },
+        unsafe { cf_handle.CFStringGetTypeID() },
+        "key in SystemVersion.plist must be a string"
+    );
+    let value: CFStringRef = value.cast();
+
+    let mut version_str = [0u8; 32];
+    let ret = unsafe {
+        cf_handle.CFStringGetCString(
+            value,
+            version_str.as_mut_ptr().cast::<c_char>(),
+            version_str.len() as CFIndex,
+            kCFStringEncodingUTF8,
+        )
+    };
+    assert_ne!(ret, 0, "failed getting string from CFString");
+
+    let version_str =
+        CStr::from_bytes_until_nul(&version_str).expect("failed converting CFString to CStr");
+
+    Some(parse_os_version(version_str.to_bytes()).unwrap_or_else(|err| {
+        panic!(
+            "failed parsing version from PList ({}): {err}",
+            ByteStr::new(version_str.to_bytes())
+        )
+    }))
+}
+
+/// Parse an OS version from a bytestring like b"10.1" or b"14.3.7".
+fn parse_os_version(version: &[u8]) -> Result<OSVersion, ParseIntError> {
+    if let Some((major, minor)) = version.split_once(|&b| b == b'.') {
+        let major = u16::from_ascii(major)?;
+        if let Some((minor, patch)) = minor.split_once(|&b| b == b'.') {
+            let minor = u8::from_ascii(minor)?;
+            let patch = u8::from_ascii(patch)?;
+            Ok(pack_os_version(major, minor, patch))
+        } else {
+            let minor = u8::from_ascii(minor)?;
+            Ok(pack_os_version(major, minor, 0))
+        }
+    } else {
+        let major = u16::from_ascii(version)?;
+        Ok(pack_os_version(major, 0, 0))
+    }
+}
+
+/// Get a path relative to the root directory in which all files for the current env are located.
+fn root_relative(path: &str) -> Cow<'_, Path> {
+    if cfg!(target_abi = "sim") {
+        let mut root = PathBuf::from(env::var_os("IPHONE_SIMULATOR_ROOT").expect(
+            "environment variable `IPHONE_SIMULATOR_ROOT` must be set when executing under simulator",
+        ));
+        // Convert absolute path to relative path, to make the `.push` work as expected.
+        root.push(Path::new(path).strip_prefix("/").unwrap());
+        root.into()
+    } else {
+        Path::new(path).into()
+    }
+}
+
+struct Deferred<F: FnMut()>(F);
+
+impl<F: FnMut()> Drop for Deferred<F> {
+    fn drop(&mut self) {
+        (self.0)();
+    }
+}
diff --git a/library/std/src/sys/platform_version/darwin/public_extern.rs b/library/std/src/sys/platform_version/darwin/public_extern.rs
new file mode 100644
index 00000000000..967cdb4920f
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/public_extern.rs
@@ -0,0 +1,151 @@
+//! # Runtime version checking ABI for other compilers.
+//!
+//! The symbols in this file are useful for us to expose to allow linking code written in the
+//! following languages when using their version checking functionality:
+//! - Clang's `__builtin_available` macro.
+//! - Objective-C's `@available`.
+//! - Swift's `#available`,
+//!
+//! Without Rust exposing these symbols, the user would encounter a linker error when linking to
+//! C/Objective-C/Swift libraries using these features.
+//!
+//! The presence of these symbols is mostly considered a quality-of-implementation detail, and
+//! should not be relied upon to be available. The intended effect is that linking with code built
+//! with Clang's `__builtin_available` (or similar) will continue to work. For example, we may
+//! decide to remove `__isOSVersionAtLeast` if support for Clang 11 (Xcode 11) is dropped.
+//!
+//! ## Background
+//!
+//! The original discussion of this feature can be found at:
+//! - <https://lists.llvm.org/pipermail/cfe-dev/2016-July/049851.html>
+//! - <https://reviews.llvm.org/D27827>
+//! - <https://reviews.llvm.org/D30136>
+//!
+//! And the upstream implementation of these can be found in `compiler-rt`:
+//! <https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0/compiler-rt/lib/builtins/os_version_check.c>
+//!
+//! Ideally, these symbols should probably have been a part of Apple's `libSystem.dylib`, both
+//! because their implementation is quite complex, using allocation, environment variables, file
+//! access and dynamic library loading (and emitting all of this into every binary).
+//!
+//! The reason why Apple chose to not do that originally is lost to the sands of time, but a good
+//! reason would be that implementing it as part of `compiler-rt` allowed them to back-deploy this
+//! to older OSes immediately.
+//!
+//! In Rust's case, while we may provide a feature similar to `@available` in the future, we will
+//! probably do so as a macro exposed by `std` (and not as a compiler builtin). So implementing this
+//! in `std` makes sense, since then we can implement it using `std` utilities, and we can avoid
+//! having `compiler-builtins` depend on `libSystem.dylib`.
+//!
+//! This does mean that users that attempt to link C/Objective-C/Swift code _and_ use `#![no_std]`
+//! in all their crates may get a linker error because these symbols are missing. Using `no_std` is
+//! quite uncommon on Apple systems though, so it's probably fine to not support this use-case.
+//!
+//! The workaround would be to link `libclang_rt.osx.a` or otherwise use Clang's `compiler-rt`.
+//!
+//! See also discussion in <https://github.com/rust-lang/compiler-builtins/pull/794>.
+//!
+//! ## Implementation details
+//!
+//! NOTE: Since macOS 10.15, `libSystem.dylib` _has_ actually provided the undocumented
+//! `_availability_version_check` via `libxpc` for doing the version lookup (zippered, which is why
+//! it requires a platform parameter to differentiate between macOS and Mac Catalyst), though its
+//! usage may be a bit dangerous, see:
+//! - <https://reviews.llvm.org/D150397>
+//! - <https://github.com/llvm/llvm-project/issues/64227>
+//!
+//! Besides, we'd need to implement the version lookup via PList to support older versions anyhow,
+//! so we might as well use that everywhere (since it can also be optimized more after inlining).
+
+#![allow(non_snake_case)]
+
+use super::{current_version, pack_i32_os_version};
+
+/// Whether the current platform's OS version is higher than or equal to the given version.
+///
+/// The first argument is the _base_ Mach-O platform (i.e. `PLATFORM_MACOS`, `PLATFORM_IOS`, etc.,
+/// but not `PLATFORM_IOSSIMULATOR` or `PLATFORM_MACCATALYST`) of the invoking binary.
+///
+/// Arguments are specified statically by Clang. Inlining with LTO should allow the versions to be
+/// combined into a single `u32`, which should make comparisons faster, and should make the
+/// `BASE_TARGET_PLATFORM` check a no-op.
+//
+// SAFETY: The signature is the same as what Clang expects, and we export weakly to allow linking
+// both this and `libclang_rt.*.a`, similar to how `compiler-builtins` does it:
+// https://github.com/rust-lang/compiler-builtins/blob/0.1.113/src/macros.rs#L494
+//
+// NOTE: This symbol has a workaround in the compiler's symbol mangling to avoid mangling it, while
+// still not exposing it from non-cdylib (like `#[no_mangle]` would).
+#[rustc_std_internal_symbol]
+// extern "C" is correct, Clang assumes the function cannot unwind:
+// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0/clang/lib/CodeGen/CGObjC.cpp#L3980
+//
+// If an error happens in this, we instead abort the process.
+pub(super) extern "C" fn __isPlatformVersionAtLeast(
+    platform: i32,
+    major: i32,
+    minor: i32,
+    subminor: i32,
+) -> i32 {
+    let version = pack_i32_os_version(major, minor, subminor);
+
+    // Mac Catalyst is a technology that allows macOS to run in a different "mode" that closely
+    // resembles iOS (and has iOS libraries like UIKit available).
+    //
+    // (Apple has added a "Designed for iPad" mode later on that allows running iOS apps
+    // natively, but we don't need to think too much about those, since they link to
+    // iOS-specific system binaries as well).
+    //
+    // To support Mac Catalyst, Apple added the concept of a "zippered" binary, which is a single
+    // binary that can be run on both macOS and Mac Catalyst (has two `LC_BUILD_VERSION` Mach-O
+    // commands, one set to `PLATFORM_MACOS` and one to `PLATFORM_MACCATALYST`).
+    //
+    // Most system libraries are zippered, which allows re-use across macOS and Mac Catalyst.
+    // This includes the `libclang_rt.osx.a` shipped with Xcode! This means that `compiler-rt`
+    // can't statically know whether it's compiled for macOS or Mac Catalyst, and thus this new
+    // API (which replaces `__isOSVersionAtLeast`) is needed.
+    //
+    // In short:
+    //      normal  binary calls  normal  compiler-rt --> `__isOSVersionAtLeast` was enough
+    //      normal  binary calls zippered compiler-rt --> `__isPlatformVersionAtLeast` required
+    //     zippered binary calls zippered compiler-rt --> `__isPlatformOrVariantPlatformVersionAtLeast` called
+
+    // FIXME(madsmtm): `rustc` doesn't support zippered binaries yet, see rust-lang/rust#131216.
+    // But once it does, we need the pre-compiled `std` shipped with rustup to be zippered, and thus
+    // we also need to handle the `platform` difference here:
+    //
+    // if cfg!(target_os = "macos") && platform == 2 /* PLATFORM_IOS */ && cfg!(zippered) {
+    //     return (version.to_u32() <= current_ios_version()) as i32;
+    // }
+    //
+    // `__isPlatformOrVariantPlatformVersionAtLeast` would also need to be implemented.
+
+    // The base Mach-O platform for the current target.
+    const BASE_TARGET_PLATFORM: i32 = if cfg!(target_os = "macos") {
+        1 // PLATFORM_MACOS
+    } else if cfg!(target_os = "ios") {
+        2 // PLATFORM_IOS
+    } else if cfg!(target_os = "tvos") {
+        3 // PLATFORM_TVOS
+    } else if cfg!(target_os = "watchos") {
+        4 // PLATFORM_WATCHOS
+    } else if cfg!(target_os = "visionos") {
+        11 // PLATFORM_VISIONOS
+    } else {
+        0 // PLATFORM_UNKNOWN
+    };
+    debug_assert_eq!(
+        platform, BASE_TARGET_PLATFORM,
+        "invalid platform provided to __isPlatformVersionAtLeast",
+    );
+
+    (version <= current_version()) as i32
+}
+
+/// Old entry point for availability. Used when compiling with older Clang versions.
+// SAFETY: Same as for `__isPlatformVersionAtLeast`.
+#[rustc_std_internal_symbol]
+pub(super) extern "C" fn __isOSVersionAtLeast(major: i32, minor: i32, subminor: i32) -> i32 {
+    let version = pack_i32_os_version(major, minor, subminor);
+    (version <= current_version()) as i32
+}
diff --git a/library/std/src/sys/platform_version/darwin/tests.rs b/library/std/src/sys/platform_version/darwin/tests.rs
new file mode 100644
index 00000000000..76dc4482c98
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/tests.rs
@@ -0,0 +1,379 @@
+use super::public_extern::*;
+use super::*;
+use crate::process::Command;
+
+#[test]
+fn test_general_available() {
+    // Lowest version always available.
+    assert_eq!(__isOSVersionAtLeast(0, 0, 0), 1);
+    // This high version never available.
+    assert_eq!(__isOSVersionAtLeast(9999, 99, 99), 0);
+}
+
+#[test]
+fn test_saturating() {
+    // Higher version than supported by OSVersion -> make sure we saturate.
+    assert_eq!(__isOSVersionAtLeast(0x10000, 0, 0), 0);
+}
+
+#[test]
+#[cfg_attr(not(target_os = "macos"), ignore = "`sw_vers` is only available on host macOS")]
+fn compare_against_sw_vers() {
+    let sw_vers = Command::new("sw_vers").arg("-productVersion").output().unwrap().stdout;
+    let sw_vers = String::from_utf8(sw_vers).unwrap();
+    let mut sw_vers = sw_vers.trim().split('.');
+
+    let major: i32 = sw_vers.next().unwrap().parse().unwrap();
+    let minor: i32 = sw_vers.next().unwrap_or("0").parse().unwrap();
+    let subminor: i32 = sw_vers.next().unwrap_or("0").parse().unwrap();
+    assert_eq!(sw_vers.count(), 0);
+
+    // Current version is available
+    assert_eq!(__isOSVersionAtLeast(major, minor, subminor), 1);
+
+    // One lower is available
+    assert_eq!(__isOSVersionAtLeast(major, minor, subminor.saturating_sub(1)), 1);
+    assert_eq!(__isOSVersionAtLeast(major, minor.saturating_sub(1), subminor), 1);
+    assert_eq!(__isOSVersionAtLeast(major.saturating_sub(1), minor, subminor), 1);
+
+    // One higher isn't available
+    assert_eq!(__isOSVersionAtLeast(major, minor, subminor + 1), 0);
+    assert_eq!(__isOSVersionAtLeast(major, minor + 1, subminor), 0);
+    assert_eq!(__isOSVersionAtLeast(major + 1, minor, subminor), 0);
+
+    // Test directly against the lookup
+    assert_eq!(lookup_version().get(), pack_os_version(major as _, minor as _, subminor as _));
+}
+
+#[test]
+fn sysctl_same_as_in_plist() {
+    if let Some(version) = version_from_sysctl() {
+        assert_eq!(version, version_from_plist());
+    }
+}
+
+#[test]
+fn lookup_idempotent() {
+    let version = lookup_version();
+    for _ in 0..10 {
+        assert_eq!(version, lookup_version());
+    }
+}
+
+/// Test parsing a bunch of different PLists found in the wild, to ensure that
+/// if we decide to parse it without CoreFoundation in the future, that it
+/// would continue to work, even on older platforms.
+#[test]
+fn parse_plist() {
+    #[track_caller]
+    fn check(
+        (major, minor, patch): (u16, u8, u8),
+        ios_version: Option<(u16, u8, u8)>,
+        plist: &str,
+    ) {
+        let expected = if cfg!(target_os = "ios") {
+            if let Some((ios_major, ios_minor, ios_patch)) = ios_version {
+                pack_os_version(ios_major, ios_minor, ios_patch)
+            } else if cfg!(target_abi = "macabi") {
+                // Skip checking iOS version on Mac Catalyst.
+                return;
+            } else {
+                // iOS version will be parsed from ProductVersion
+                pack_os_version(major, minor, patch)
+            }
+        } else {
+            pack_os_version(major, minor, patch)
+        };
+        let cf_handle = CFHandle::new();
+        assert_eq!(expected, parse_version_from_plist(&cf_handle, plist.as_bytes()));
+    }
+
+    // macOS 10.3.0
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>ProductBuildVersion</key>
+            <string>7B85</string>
+            <key>ProductCopyright</key>
+            <string>Apple Computer, Inc. 1983-2003</string>
+            <key>ProductName</key>
+            <string>Mac OS X</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>10.3</string>
+            <key>ProductVersion</key>
+            <string>10.3</string>
+        </dict>
+        </plist>
+    "#;
+    check((10, 3, 0), None, plist);
+
+    // macOS 10.7.5
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>ProductBuildVersion</key>
+            <string>11G63</string>
+            <key>ProductCopyright</key>
+            <string>1983-2012 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Mac OS X</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>10.7.5</string>
+            <key>ProductVersion</key>
+            <string>10.7.5</string>
+        </dict>
+        </plist>
+    "#;
+    check((10, 7, 5), None, plist);
+
+    // macOS 14.7.4
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>6A558D8A-E2EA-11EF-A1D3-6222CAA672A8</string>
+            <key>ProductBuildVersion</key>
+            <string>23H420</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>macOS</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>14.7.4</string>
+            <key>ProductVersion</key>
+            <string>14.7.4</string>
+            <key>iOSSupportVersion</key>
+            <string>17.7</string>
+        </dict>
+        </plist>
+    "#;
+    check((14, 7, 4), Some((17, 7, 0)), plist);
+
+    // SystemVersionCompat.plist on macOS 14.7.4
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>6A558D8A-E2EA-11EF-A1D3-6222CAA672A8</string>
+            <key>ProductBuildVersion</key>
+            <string>23H420</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Mac OS X</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>10.16</string>
+            <key>ProductVersion</key>
+            <string>10.16</string>
+            <key>iOSSupportVersion</key>
+            <string>17.7</string>
+        </dict>
+        </plist>
+    "#;
+    check((10, 16, 0), Some((17, 7, 0)), plist);
+
+    // macOS 15.4 Beta 24E5238a
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>67A50F62-00DA-11F0-BDB6-F99BB8310D2A</string>
+            <key>ProductBuildVersion</key>
+            <string>24E5238a</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>macOS</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>15.4</string>
+            <key>ProductVersion</key>
+            <string>15.4</string>
+            <key>iOSSupportVersion</key>
+            <string>18.4</string>
+        </dict>
+        </plist>
+    "#;
+    check((15, 4, 0), Some((18, 4, 0)), plist);
+
+    // iOS Simulator 17.5
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>210B8A2C-09C3-11EF-9DB8-273A64AEFA1C</string>
+            <key>ProductBuildVersion</key>
+            <string>21F79</string>
+            <key>ProductCopyright</key>
+            <string>1983-2024 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>iPhone OS</string>
+            <key>ProductVersion</key>
+            <string>17.5</string>
+        </dict>
+        </plist>
+    "#;
+    check((17, 5, 0), None, plist);
+
+    // visionOS Simulator 2.3
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>57CEFDE6-D079-11EF-837C-8B8C7961D0AC</string>
+            <key>ProductBuildVersion</key>
+            <string>22N895</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>xrOS</string>
+            <key>ProductVersion</key>
+            <string>2.3</string>
+            <key>SystemImageID</key>
+            <string>D332C7F1-08DF-4DD9-8122-94EF39A1FB92</string>
+            <key>iOSSupportVersion</key>
+            <string>18.3</string>
+        </dict>
+        </plist>
+    "#;
+    check((2, 3, 0), Some((18, 3, 0)), plist);
+
+    // tvOS Simulator 18.2
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>617587B0-B059-11EF-BE70-4380EDE44645</string>
+            <key>ProductBuildVersion</key>
+            <string>22K154</string>
+            <key>ProductCopyright</key>
+            <string>1983-2024 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Apple TVOS</string>
+            <key>ProductVersion</key>
+            <string>18.2</string>
+            <key>SystemImageID</key>
+            <string>8BB5A425-33F0-4821-9F93-40E7ED92F4E0</string>
+        </dict>
+        </plist>
+    "#;
+    check((18, 2, 0), None, plist);
+
+    // watchOS Simulator 11.2
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>BAAE2D54-B122-11EF-BF78-C6C6836B724A</string>
+            <key>ProductBuildVersion</key>
+            <string>22S99</string>
+            <key>ProductCopyright</key>
+            <string>1983-2024 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Watch OS</string>
+            <key>ProductVersion</key>
+            <string>11.2</string>
+            <key>SystemImageID</key>
+            <string>79F773E2-2041-43B4-98EE-FAE52402AE95</string>
+        </dict>
+        </plist>
+    "#;
+    check((11, 2, 0), None, plist);
+
+    // iOS 9.3.6
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>ProductBuildVersion</key>
+            <string>13G37</string>
+            <key>ProductCopyright</key>
+            <string>1983-2019 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>iPhone OS</string>
+            <key>ProductVersion</key>
+            <string>9.3.6</string>
+        </dict>
+        </plist>
+    "#;
+    check((9, 3, 6), None, plist);
+}
+
+#[test]
+#[should_panic = "SystemVersion.plist did not contain a dictionary at the top level"]
+fn invalid_plist() {
+    let cf_handle = CFHandle::new();
+    let _ = parse_version_from_plist(&cf_handle, b"INVALID");
+}
+
+#[test]
+#[cfg_attr(
+    target_abi = "macabi",
+    should_panic = "expected iOSSupportVersion in SystemVersion.plist"
+)]
+#[cfg_attr(
+    not(target_abi = "macabi"),
+    should_panic = "expected ProductVersion in SystemVersion.plist"
+)]
+fn empty_plist() {
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+        </dict>
+        </plist>
+    "#;
+    let cf_handle = CFHandle::new();
+    let _ = parse_version_from_plist(&cf_handle, plist.as_bytes());
+}
+
+#[test]
+fn parse_version() {
+    #[track_caller]
+    fn check(major: u16, minor: u8, patch: u8, version: &str) {
+        assert_eq!(
+            pack_os_version(major, minor, patch),
+            parse_os_version(version.as_bytes()).unwrap()
+        )
+    }
+
+    check(0, 0, 0, "0");
+    check(0, 0, 0, "0.0.0");
+    check(1, 0, 0, "1");
+    check(1, 2, 0, "1.2");
+    check(1, 2, 3, "1.2.3");
+    check(9999, 99, 99, "9999.99.99");
+
+    // Check leading zeroes
+    check(10, 0, 0, "010");
+    check(10, 20, 0, "010.020");
+    check(10, 20, 30, "010.020.030");
+    check(10000, 100, 100, "000010000.00100.00100");
+
+    // Too many parts
+    assert!(parse_os_version(b"1.2.3.4").is_err());
+
+    // Empty
+    assert!(parse_os_version(b"").is_err());
+
+    // Invalid digit
+    assert!(parse_os_version(b"A.B").is_err());
+
+    // Missing digits
+    assert!(parse_os_version(b".").is_err());
+    assert!(parse_os_version(b".1").is_err());
+    assert!(parse_os_version(b"1.").is_err());
+
+    // Too large
+    assert!(parse_os_version(b"100000").is_err());
+    assert!(parse_os_version(b"1.1000").is_err());
+    assert!(parse_os_version(b"1.1.1000").is_err());
+}
diff --git a/library/std/src/sys/platform_version/mod.rs b/library/std/src/sys/platform_version/mod.rs
new file mode 100644
index 00000000000..88896c97ea3
--- /dev/null
+++ b/library/std/src/sys/platform_version/mod.rs
@@ -0,0 +1,13 @@
+//! Runtime lookup of operating system / platform version.
+//!
+//! Related to [RFC 3750](https://github.com/rust-lang/rfcs/pull/3750), which
+//! does version detection at compile-time.
+//!
+//! See also the `os_info` crate.
+
+#[cfg(target_vendor = "apple")]
+mod darwin;
+
+// In the future, we could expand this module with:
+// - `RtlGetVersion` on Windows.
+// - `__system_property_get` on Android.
diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs
index 314f226f07b..7436e4d9de4 100644
--- a/library/std/src/sys/stdio/mod.rs
+++ b/library/std/src/sys/stdio/mod.rs
@@ -29,9 +29,13 @@ cfg_select! {
         mod uefi;
         pub use uefi::*;
     }
-    target_os = "wasi" => {
-        mod wasi;
-        pub use wasi::*;
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use wasip1::*;
+    }
+    all(target_os = "wasi", target_env = "p2") => {
+        mod wasip2;
+        pub use wasip2::*;
     }
     target_os = "xous" => {
         mod xous;
diff --git a/library/std/src/sys/stdio/wasi.rs b/library/std/src/sys/stdio/wasip1.rs
index b70efd026f9..b70efd026f9 100644
--- a/library/std/src/sys/stdio/wasi.rs
+++ b/library/std/src/sys/stdio/wasip1.rs
diff --git a/library/std/src/sys/stdio/wasip2.rs b/library/std/src/sys/stdio/wasip2.rs
new file mode 100644
index 00000000000..1fcb49a083d
--- /dev/null
+++ b/library/std/src/sys/stdio/wasip2.rs
@@ -0,0 +1,120 @@
+use wasip2::cli;
+use wasip2::io::streams::{Error, InputStream, OutputStream, StreamError};
+
+use crate::io::{self, BorrowedBuf, BorrowedCursor};
+
+pub struct Stdin(Option<InputStream>);
+pub struct Stdout(Option<OutputStream>);
+pub struct Stderr(Option<OutputStream>);
+
+fn error_to_io(err: Error) -> io::Error {
+    // There exists a function in `wasi:filesystem` to optionally acquire an
+    // error code from an error, but the streams in use in this module are
+    // exclusively used with stdio meaning that a filesystem error is not
+    // possible here.
+    //
+    // In lieu of an error code, which WASIp2 does not specify, this instead
+    // carries along the `to_debug_string` implementation that the host
+    // supplies. If this becomes too expensive in the future this could also
+    // become `io::Error::from_raw_os_error(libc::EIO)` or similar.
+    io::Error::new(io::ErrorKind::Other, err.to_debug_string())
+}
+
+impl Stdin {
+    pub const fn new() -> Stdin {
+        Stdin(None)
+    }
+
+    fn stream(&mut self) -> &InputStream {
+        self.0.get_or_insert_with(cli::stdin::get_stdin)
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(data);
+        self.read_buf(buf.unfilled())?;
+        Ok(buf.len())
+    }
+
+    fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
+        match self.stream().blocking_read(u64::try_from(buf.capacity()).unwrap()) {
+            Ok(result) => {
+                buf.append(&result);
+                Ok(())
+            }
+            Err(StreamError::Closed) => Ok(()),
+            Err(StreamError::LastOperationFailed(e)) => Err(error_to_io(e)),
+        }
+    }
+}
+
+impl Stdout {
+    pub const fn new() -> Stdout {
+        Stdout(None)
+    }
+
+    fn stream(&mut self) -> &OutputStream {
+        self.0.get_or_insert_with(cli::stdout::get_stdout)
+    }
+}
+
+fn write(stream: &OutputStream, buf: &[u8]) -> io::Result<usize> {
+    // WASIp2's `blocking_write_and_flush` function is defined as accepting no
+    // more than 4096 bytes. Larger writes can be issued by manually using
+    // `check_write`, `write`, and `blocking_flush`, but for now just go ahead
+    // and use `blocking_write_and_flush` and report a short write and let a
+    // higher level loop over the result.
+    const MAX: usize = 4096;
+    let buf = &buf[..buf.len().min(MAX)];
+    match stream.blocking_write_and_flush(buf) {
+        Ok(()) => Ok(buf.len()),
+        Err(StreamError::Closed) => Ok(0),
+        Err(StreamError::LastOperationFailed(e)) => Err(error_to_io(e)),
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        write(self.stream(), data)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // Note that `OutputStream` has a `flush` function but for stdio all
+        // writes are accompanied with a flush which means that this flush
+        // doesn't need to do anything.
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub const fn new() -> Stderr {
+        Stderr(None)
+    }
+
+    fn stream(&mut self) -> &OutputStream {
+        self.0.get_or_insert_with(cli::stderr::get_stderr)
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        write(self.stream(), data)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // See `Stdout::flush` for why this is a noop.
+        Ok(())
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    // WASIp2 stdio streams are always available so ebadf never shows up.
+    false
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Some(Stderr::new())
+}
diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs
index c61a8ec4d20..c29d803b25e 100644
--- a/library/std/tests/floats/f32.rs
+++ b/library/std/tests/floats/f32.rs
@@ -79,8 +79,8 @@ fn test_log() {
     let nan: f32 = f32::NAN;
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
-    assert_approx_eq!(10.0f32.log(10.0), 1.0, APPROX_DELTA);
-    assert_approx_eq!(2.3f32.log(3.5), 0.664858, APPROX_DELTA);
+    assert_approx_eq!(10.0f32.log(10.0), 1.0);
+    assert_approx_eq!(2.3f32.log(3.5), 0.664858);
     assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA);
     assert!(1.0f32.log(1.0).is_nan());
     assert!(1.0f32.log(-13.9).is_nan());
@@ -140,10 +140,10 @@ fn test_asinh() {
     assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
     assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
     // regression test for the catastrophic cancellation fixed in 72486
-    assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
+    assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32, APPROX_DELTA);
 
     // test for low accuracy from issue 104548
-    assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh());
+    assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh(), APPROX_DELTA);
     // mul needed for approximate comparison to be meaningful
     assert_approx_eq!(1.0f32, 1e-15f32.sinh().asinh() * 1e15f32);
 }
@@ -196,8 +196,8 @@ fn test_gamma() {
     assert_approx_eq!(1.0f32.gamma(), 1.0f32);
     assert_approx_eq!(2.0f32.gamma(), 1.0f32);
     assert_approx_eq!(3.0f32.gamma(), 2.0f32);
-    assert_approx_eq!(4.0f32.gamma(), 6.0f32);
-    assert_approx_eq!(5.0f32.gamma(), 24.0f32);
+    assert_approx_eq!(4.0f32.gamma(), 6.0f32, APPROX_DELTA);
+    assert_approx_eq!(5.0f32.gamma(), 24.0f32, APPROX_DELTA);
     assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt());
     assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt());
     assert_eq!(0.0f32.gamma(), f32::INFINITY);
@@ -218,7 +218,7 @@ fn test_ln_gamma() {
     assert_eq!(2.0f32.ln_gamma().1, 1);
     assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln());
     assert_eq!(3.0f32.ln_gamma().1, 1);
-    assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln());
+    assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), APPROX_DELTA);
     assert_eq!((-0.5f32).ln_gamma().1, -1);
 }
 
diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs
index e1576a0d423..fa76c50597b 100644
--- a/library/std/tests/path.rs
+++ b/library/std/tests/path.rs
@@ -1,4 +1,4 @@
-#![feature(clone_to_uninit, path_add_extension, maybe_uninit_slice, normalize_lexically)]
+#![feature(clone_to_uninit, maybe_uninit_slice, normalize_lexically)]
 
 use std::clone::CloneToUninit;
 use std::ffi::OsStr;
@@ -2526,3 +2526,9 @@ fn normalize_lexically() {
         check_err(r"\\?\UNC\server\share\a\..\..");
     }
 }
+
+#[test]
+/// See issue#146183
+fn compare_path_to_str() {
+    assert!(&PathBuf::from("x") == "x");
+}
diff --git a/package-lock.json b/package-lock.json
index 44e8b65c28d..def0cfa86a5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,7 +5,7 @@
   "packages": {
     "": {
       "dependencies": {
-        "browser-ui-test": "^0.21.3",
+        "browser-ui-test": "^0.22.0",
         "es-check": "^6.2.1",
         "eslint": "^8.57.1",
         "eslint-js": "github:eslint/js",
@@ -37,8 +37,6 @@
     },
     "node_modules/@caporal/core": {
       "version": "2.0.7",
-      "resolved": "https://registry.npmjs.org/@caporal/core/-/core-2.0.7.tgz",
-      "integrity": "sha512-OvKBEidoXUGT28RP3USXFdLgiR5kGCHfRXR1uBQznyxBHaWjGcpH+G1chRqyIVT82pQoJiauOZRIGlrpyAbRYQ==",
       "license": "MIT",
       "dependencies": {
         "@types/glob": "^7.1.1",
@@ -61,8 +59,6 @@
     },
     "node_modules/@colors/colors": {
       "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
-      "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
       "license": "MIT",
       "engines": {
         "node": ">=0.1.90"
@@ -70,8 +66,6 @@
     },
     "node_modules/@dabh/diagnostics": {
       "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
-      "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
       "license": "MIT",
       "dependencies": {
         "colorspace": "1.1.x",
@@ -81,8 +75,6 @@
     },
     "node_modules/@eslint-community/eslint-utils": {
       "version": "4.7.0",
-      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
-      "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
       "license": "MIT",
       "dependencies": {
         "eslint-visitor-keys": "^3.4.3"
@@ -99,8 +91,6 @@
     },
     "node_modules/@eslint-community/regexpp": {
       "version": "4.12.1",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
-      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
       "license": "MIT",
       "engines": {
         "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
@@ -108,8 +98,6 @@
     },
     "node_modules/@eslint/eslintrc": {
       "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
-      "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
       "license": "MIT",
       "dependencies": {
         "ajv": "^6.12.4",
@@ -131,8 +119,6 @@
     },
     "node_modules/@eslint/js": {
       "version": "8.57.1",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
-      "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
       "license": "MIT",
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -140,9 +126,6 @@
     },
     "node_modules/@humanwhocodes/config-array": {
       "version": "0.13.0",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
-      "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
-      "deprecated": "Use @eslint/config-array instead",
       "license": "Apache-2.0",
       "dependencies": {
         "@humanwhocodes/object-schema": "^2.0.3",
@@ -155,8 +138,6 @@
     },
     "node_modules/@humanwhocodes/module-importer": {
       "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
       "license": "Apache-2.0",
       "engines": {
         "node": ">=12.22"
@@ -168,15 +149,10 @@
     },
     "node_modules/@humanwhocodes/object-schema": {
       "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
-      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
-      "deprecated": "Use @eslint/object-schema instead",
       "license": "BSD-3-Clause"
     },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
       "license": "MIT",
       "dependencies": {
         "@nodelib/fs.stat": "2.0.5",
@@ -188,8 +164,6 @@
     },
     "node_modules/@nodelib/fs.stat": {
       "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
       "license": "MIT",
       "engines": {
         "node": ">= 8"
@@ -197,8 +171,6 @@
     },
     "node_modules/@nodelib/fs.walk": {
       "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
       "license": "MIT",
       "dependencies": {
         "@nodelib/fs.scandir": "2.1.5",
@@ -238,8 +210,6 @@
     },
     "node_modules/@types/glob": {
       "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
-      "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
       "license": "MIT",
       "dependencies": {
         "@types/minimatch": "*",
@@ -248,32 +218,22 @@
     },
     "node_modules/@types/lodash": {
       "version": "4.17.20",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
-      "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
       "license": "MIT"
     },
     "node_modules/@types/minimatch": {
       "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
-      "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
       "license": "MIT"
     },
     "node_modules/@types/node": {
       "version": "13.9.3",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.3.tgz",
-      "integrity": "sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA==",
       "license": "MIT"
     },
     "node_modules/@types/table": {
       "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/@types/table/-/table-5.0.0.tgz",
-      "integrity": "sha512-fQLtGLZXor264zUPWI95WNDsZ3QV43/c0lJpR/h1hhLJumXRmHNsrvBfEzW2YMhb0EWCsn4U6h82IgwsajAuTA==",
       "license": "MIT"
     },
     "node_modules/@types/tabtab": {
       "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@types/tabtab/-/tabtab-3.0.4.tgz",
-      "integrity": "sha512-gmh8JsmIYPGRqk8Xb4dmulV37TpLwg0Quo3GJ0LgEcl4v0O92F14PGebBd7LHv9GBEw2KbmBSrvU0/NzIy5AoA==",
       "license": "MIT",
       "dependencies": {
         "@types/node": "*"
@@ -281,14 +241,10 @@
     },
     "node_modules/@types/triple-beam": {
       "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
-      "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
       "license": "MIT"
     },
     "node_modules/@types/wrap-ansi": {
       "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz",
-      "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==",
       "license": "MIT"
     },
     "node_modules/@types/yauzl": {
@@ -303,14 +259,10 @@
     },
     "node_modules/@ungap/structured-clone": {
       "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
-      "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
       "license": "ISC"
     },
     "node_modules/acorn": {
       "version": "8.15.0",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
-      "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
       "license": "MIT",
       "bin": {
         "acorn": "bin/acorn"
@@ -321,8 +273,6 @@
     },
     "node_modules/acorn-jsx": {
       "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
-      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
       "license": "MIT",
       "peerDependencies": {
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
@@ -339,8 +289,6 @@
     },
     "node_modules/ajv": {
       "version": "6.12.6",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
       "license": "MIT",
       "dependencies": {
         "fast-deep-equal": "^3.1.1",
@@ -355,8 +303,6 @@
     },
     "node_modules/ansi-escapes": {
       "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
-      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -364,8 +310,6 @@
     },
     "node_modules/ansi-regex": {
       "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -373,8 +317,6 @@
     },
     "node_modules/ansi-styles": {
       "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
       "license": "MIT",
       "dependencies": {
         "color-convert": "^2.0.1"
@@ -388,8 +330,6 @@
     },
     "node_modules/argparse": {
       "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
       "license": "Python-2.0"
     },
     "node_modules/ast-types": {
@@ -406,8 +346,6 @@
     },
     "node_modules/astral-regex": {
       "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
-      "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -415,8 +353,6 @@
     },
     "node_modules/async": {
       "version": "3.2.6",
-      "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
-      "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
       "license": "MIT"
     },
     "node_modules/b4a": {
@@ -427,21 +363,19 @@
     },
     "node_modules/balanced-match": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
       "license": "MIT"
     },
     "node_modules/bare-events": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.0.tgz",
-      "integrity": "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg==",
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz",
+      "integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==",
       "license": "Apache-2.0",
       "optional": true
     },
     "node_modules/bare-fs": {
-      "version": "4.1.6",
-      "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.6.tgz",
-      "integrity": "sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ==",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.2.3.tgz",
+      "integrity": "sha512-1aGs5pRVLToMQ79elP+7cc0u0s/wXAzfBv/7hDloT7WFggLqECCas5qqPky7WHCFdsBH5WDq6sD4fAoz5sJbtA==",
       "license": "Apache-2.0",
       "optional": true,
       "dependencies": {
@@ -462,9 +396,9 @@
       }
     },
     "node_modules/bare-os": {
-      "version": "3.6.1",
-      "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz",
-      "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==",
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz",
+      "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==",
       "license": "Apache-2.0",
       "optional": true,
       "engines": {
@@ -482,9 +416,9 @@
       }
     },
     "node_modules/bare-stream": {
-      "version": "2.6.5",
-      "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz",
-      "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==",
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz",
+      "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==",
       "license": "Apache-2.0",
       "optional": true,
       "dependencies": {
@@ -534,8 +468,6 @@
     },
     "node_modules/brace-expansion": {
       "version": "1.1.12",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
-      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
       "license": "MIT",
       "dependencies": {
         "balanced-match": "^1.0.0",
@@ -544,8 +476,6 @@
     },
     "node_modules/braces": {
       "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
-      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
       "license": "MIT",
       "dependencies": {
         "fill-range": "^7.1.1"
@@ -555,9 +485,9 @@
       }
     },
     "node_modules/browser-ui-test": {
-      "version": "0.21.3",
-      "resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.21.1.tgz",
-      "integrity": "sha512-b3a9mhALAmbP+GifoN/c295RPyuyfIUFMz0DtlBHbeDW5PYQTMHZZJtm7R2UyP6JiIQSkR+7227sS3maMGMUTg==",
+      "version": "0.22.0",
+      "resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.22.0.tgz",
+      "integrity": "sha512-p/C02TMybTDKsAjpGOdnyNC0Q25KDae/fKMnvHaqcJ0tXRqNKwndW2Ltq7HTmin5xqg8GGOmysEgWTZkXu6pfA==",
       "license": "MIT",
       "dependencies": {
         "css-unit-converter": "^1.1.2",
@@ -604,8 +534,6 @@
     },
     "node_modules/callsites": {
       "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
       "license": "MIT",
       "engines": {
         "node": ">=6"
@@ -613,8 +541,6 @@
     },
     "node_modules/chalk": {
       "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-      "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
       "license": "MIT",
       "dependencies": {
         "ansi-styles": "^4.1.0",
@@ -626,8 +552,6 @@
     },
     "node_modules/chardet": {
       "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
-      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
       "license": "MIT"
     },
     "node_modules/chromium-bidi": {
@@ -646,8 +570,6 @@
     },
     "node_modules/cli-cursor": {
       "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
-      "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==",
       "license": "MIT",
       "dependencies": {
         "restore-cursor": "^2.0.0"
@@ -658,8 +580,6 @@
     },
     "node_modules/cli-width": {
       "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
-      "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
       "license": "ISC"
     },
     "node_modules/cliui": {
@@ -724,8 +644,6 @@
     },
     "node_modules/color": {
       "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
-      "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
       "license": "MIT",
       "dependencies": {
         "color-convert": "^1.9.3",
@@ -734,8 +652,6 @@
     },
     "node_modules/color-convert": {
       "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
       "license": "MIT",
       "dependencies": {
         "color-name": "~1.1.4"
@@ -746,14 +662,10 @@
     },
     "node_modules/color-name": {
       "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
       "license": "MIT"
     },
     "node_modules/color-string": {
       "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
-      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
       "license": "MIT",
       "dependencies": {
         "color-name": "^1.0.0",
@@ -762,8 +674,6 @@
     },
     "node_modules/color/node_modules/color-convert": {
       "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
       "license": "MIT",
       "dependencies": {
         "color-name": "1.1.3"
@@ -771,14 +681,10 @@
     },
     "node_modules/color/node_modules/color-name": {
       "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
       "license": "MIT"
     },
     "node_modules/colorspace": {
       "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
-      "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
       "license": "MIT",
       "dependencies": {
         "color": "^3.1.3",
@@ -787,8 +693,6 @@
     },
     "node_modules/concat-map": {
       "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "license": "MIT"
     },
     "node_modules/cosmiconfig": {
@@ -819,8 +723,6 @@
     },
     "node_modules/cross-spawn": {
       "version": "7.0.6",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
-      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
       "license": "MIT",
       "dependencies": {
         "path-key": "^3.1.0",
@@ -848,8 +750,6 @@
     },
     "node_modules/debug": {
       "version": "4.4.1",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
-      "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
       "license": "MIT",
       "dependencies": {
         "ms": "^2.1.3"
@@ -865,8 +765,6 @@
     },
     "node_modules/deep-is": {
       "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "license": "MIT"
     },
     "node_modules/degenerator": {
@@ -891,8 +789,6 @@
     },
     "node_modules/doctrine": {
       "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
       "license": "Apache-2.0",
       "dependencies": {
         "esutils": "^2.0.2"
@@ -903,14 +799,10 @@
     },
     "node_modules/emoji-regex": {
       "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
       "license": "MIT"
     },
     "node_modules/enabled": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
-      "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
       "license": "MIT"
     },
     "node_modules/end-of-stream": {
@@ -942,8 +834,6 @@
     },
     "node_modules/es-check": {
       "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/es-check/-/es-check-6.2.1.tgz",
-      "integrity": "sha512-IPiRXUlwSTd2yMklIf9yEGe6GK5wCS8Sz1aTNHm1QSiYzI4aiq19giYbLi95tb+e0JJVKmcU0iQXQWW60a8V9A==",
       "license": "MIT",
       "dependencies": {
         "@caporal/core": "^2.0.2",
@@ -959,8 +849,6 @@
     },
     "node_modules/es6-promisify": {
       "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
-      "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==",
       "license": "MIT"
     },
     "node_modules/escalade": {
@@ -974,8 +862,6 @@
     },
     "node_modules/escape-string-regexp": {
       "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
       "license": "MIT",
       "engines": {
         "node": ">=10"
@@ -1007,9 +893,6 @@
     },
     "node_modules/eslint": {
       "version": "8.57.1",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
-      "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
-      "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
       "license": "MIT",
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
@@ -1063,15 +946,13 @@
     },
     "node_modules/eslint-js": {
       "version": "1.0.0",
-      "resolved": "git+ssh://git@github.com/eslint/js.git#5bd12e3772d361af2c4bfad774ea7bfd9caae6bc",
+      "resolved": "git+ssh://git@github.com/eslint/js.git#9e5b4fabf073b915abc56d6c14cc24177036d43e",
       "workspaces": [
         "packages/*"
       ]
     },
     "node_modules/eslint-scope": {
       "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
-      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
       "license": "BSD-2-Clause",
       "dependencies": {
         "esrecurse": "^4.3.0",
@@ -1086,8 +967,6 @@
     },
     "node_modules/eslint-visitor-keys": {
       "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
       "license": "Apache-2.0",
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -1098,8 +977,6 @@
     },
     "node_modules/eslint/node_modules/chalk": {
       "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
       "license": "MIT",
       "dependencies": {
         "ansi-styles": "^4.1.0",
@@ -1114,8 +991,6 @@
     },
     "node_modules/espree": {
       "version": "9.6.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
-      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
       "license": "BSD-2-Clause",
       "dependencies": {
         "acorn": "^8.9.0",
@@ -1144,8 +1019,6 @@
     },
     "node_modules/esquery": {
       "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
-      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
       "license": "BSD-3-Clause",
       "dependencies": {
         "estraverse": "^5.1.0"
@@ -1156,8 +1029,6 @@
     },
     "node_modules/esrecurse": {
       "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
       "license": "BSD-2-Clause",
       "dependencies": {
         "estraverse": "^5.2.0"
@@ -1168,8 +1039,6 @@
     },
     "node_modules/estraverse": {
       "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
       "license": "BSD-2-Clause",
       "engines": {
         "node": ">=4.0"
@@ -1177,8 +1046,6 @@
     },
     "node_modules/esutils": {
       "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
       "license": "BSD-2-Clause",
       "engines": {
         "node": ">=0.10.0"
@@ -1186,8 +1053,6 @@
     },
     "node_modules/external-editor": {
       "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
-      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
       "license": "MIT",
       "dependencies": {
         "chardet": "^0.7.0",
@@ -1220,8 +1085,6 @@
     },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
       "license": "MIT"
     },
     "node_modules/fast-fifo": {
@@ -1232,8 +1095,6 @@
     },
     "node_modules/fast-glob": {
       "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
-      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
       "license": "MIT",
       "dependencies": {
         "@nodelib/fs.stat": "^2.0.2",
@@ -1248,8 +1109,6 @@
     },
     "node_modules/fast-glob/node_modules/glob-parent": {
       "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
       "license": "ISC",
       "dependencies": {
         "is-glob": "^4.0.1"
@@ -1260,20 +1119,14 @@
     },
     "node_modules/fast-json-stable-stringify": {
       "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
       "license": "MIT"
     },
     "node_modules/fast-levenshtein": {
       "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "license": "MIT"
     },
     "node_modules/fastq": {
       "version": "1.19.1",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
-      "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
       "license": "ISC",
       "dependencies": {
         "reusify": "^1.0.4"
@@ -1290,14 +1143,10 @@
     },
     "node_modules/fecha": {
       "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
-      "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
       "license": "MIT"
     },
     "node_modules/figures": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
-      "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==",
       "license": "MIT",
       "dependencies": {
         "escape-string-regexp": "^1.0.5"
@@ -1308,8 +1157,6 @@
     },
     "node_modules/figures/node_modules/escape-string-regexp": {
       "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
       "license": "MIT",
       "engines": {
         "node": ">=0.8.0"
@@ -1317,8 +1164,6 @@
     },
     "node_modules/file-entry-cache": {
       "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
       "license": "MIT",
       "dependencies": {
         "flat-cache": "^3.0.4"
@@ -1329,8 +1174,6 @@
     },
     "node_modules/fill-range": {
       "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
-      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
       "license": "MIT",
       "dependencies": {
         "to-regex-range": "^5.0.1"
@@ -1341,8 +1184,6 @@
     },
     "node_modules/find-up": {
       "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
       "license": "MIT",
       "dependencies": {
         "locate-path": "^6.0.0",
@@ -1357,8 +1198,6 @@
     },
     "node_modules/flat-cache": {
       "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
-      "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
       "license": "MIT",
       "dependencies": {
         "flatted": "^3.2.9",
@@ -1371,20 +1210,14 @@
     },
     "node_modules/flatted": {
       "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
-      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
       "license": "ISC"
     },
     "node_modules/fn.name": {
       "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
-      "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
       "license": "MIT"
     },
     "node_modules/fs.realpath": {
       "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
       "license": "ISC"
     },
     "node_modules/get-caller-file": {
@@ -1427,9 +1260,6 @@
     },
     "node_modules/glob": {
       "version": "7.2.3",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-      "deprecated": "Glob versions prior to v9 are no longer supported",
       "license": "ISC",
       "dependencies": {
         "fs.realpath": "^1.0.0",
@@ -1448,8 +1278,6 @@
     },
     "node_modules/glob-parent": {
       "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
       "license": "ISC",
       "dependencies": {
         "is-glob": "^4.0.3"
@@ -1460,8 +1288,6 @@
     },
     "node_modules/globals": {
       "version": "13.24.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
-      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
       "license": "MIT",
       "dependencies": {
         "type-fest": "^0.20.2"
@@ -1475,14 +1301,10 @@
     },
     "node_modules/graphemer": {
       "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
       "license": "MIT"
     },
     "node_modules/has-flag": {
       "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -1516,8 +1338,6 @@
     },
     "node_modules/iconv-lite": {
       "version": "0.4.24",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
       "license": "MIT",
       "dependencies": {
         "safer-buffer": ">= 2.1.2 < 3"
@@ -1548,8 +1368,6 @@
     },
     "node_modules/ignore": {
       "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
-      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
       "license": "MIT",
       "engines": {
         "node": ">= 4"
@@ -1557,8 +1375,6 @@
     },
     "node_modules/import-fresh": {
       "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
-      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
       "license": "MIT",
       "dependencies": {
         "parent-module": "^1.0.0",
@@ -1573,8 +1389,6 @@
     },
     "node_modules/imurmurhash": {
       "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
       "license": "MIT",
       "engines": {
         "node": ">=0.8.19"
@@ -1582,9 +1396,6 @@
     },
     "node_modules/inflight": {
       "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-      "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
       "license": "ISC",
       "dependencies": {
         "once": "^1.3.0",
@@ -1593,14 +1404,10 @@
     },
     "node_modules/inherits": {
       "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
       "license": "ISC"
     },
     "node_modules/inquirer": {
       "version": "6.5.2",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
-      "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
       "license": "MIT",
       "dependencies": {
         "ansi-escapes": "^3.2.0",
@@ -1623,8 +1430,6 @@
     },
     "node_modules/inquirer/node_modules/ansi-regex": {
       "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
-      "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
       "license": "MIT",
       "engines": {
         "node": ">=6"
@@ -1632,8 +1437,6 @@
     },
     "node_modules/inquirer/node_modules/ansi-styles": {
       "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
       "license": "MIT",
       "dependencies": {
         "color-convert": "^1.9.0"
@@ -1644,8 +1447,6 @@
     },
     "node_modules/inquirer/node_modules/chalk": {
       "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
       "license": "MIT",
       "dependencies": {
         "ansi-styles": "^3.2.1",
@@ -1658,8 +1459,6 @@
     },
     "node_modules/inquirer/node_modules/color-convert": {
       "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
       "license": "MIT",
       "dependencies": {
         "color-name": "1.1.3"
@@ -1667,14 +1466,10 @@
     },
     "node_modules/inquirer/node_modules/color-name": {
       "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
       "license": "MIT"
     },
     "node_modules/inquirer/node_modules/escape-string-regexp": {
       "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
       "license": "MIT",
       "engines": {
         "node": ">=0.8.0"
@@ -1682,8 +1477,6 @@
     },
     "node_modules/inquirer/node_modules/has-flag": {
       "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -1691,8 +1484,6 @@
     },
     "node_modules/inquirer/node_modules/string-width": {
       "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
       "license": "MIT",
       "dependencies": {
         "is-fullwidth-code-point": "^2.0.0",
@@ -1704,8 +1495,6 @@
     },
     "node_modules/inquirer/node_modules/string-width/node_modules/ansi-regex": {
       "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
-      "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -1713,8 +1502,6 @@
     },
     "node_modules/inquirer/node_modules/string-width/node_modules/strip-ansi": {
       "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-      "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
       "license": "MIT",
       "dependencies": {
         "ansi-regex": "^3.0.0"
@@ -1725,8 +1512,6 @@
     },
     "node_modules/inquirer/node_modules/strip-ansi": {
       "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
       "license": "MIT",
       "dependencies": {
         "ansi-regex": "^4.1.0"
@@ -1737,8 +1522,6 @@
     },
     "node_modules/inquirer/node_modules/supports-color": {
       "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
       "license": "MIT",
       "dependencies": {
         "has-flag": "^3.0.0"
@@ -1748,14 +1531,10 @@
       }
     },
     "node_modules/ip-address": {
-      "version": "9.0.5",
-      "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
-      "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
+      "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
       "license": "MIT",
-      "dependencies": {
-        "jsbn": "1.1.0",
-        "sprintf-js": "^1.1.3"
-      },
       "engines": {
         "node": ">= 12"
       }
@@ -1768,8 +1547,6 @@
     },
     "node_modules/is-extglob": {
       "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
       "license": "MIT",
       "engines": {
         "node": ">=0.10.0"
@@ -1777,8 +1554,6 @@
     },
     "node_modules/is-fullwidth-code-point": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-      "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -1786,8 +1561,6 @@
     },
     "node_modules/is-glob": {
       "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
       "license": "MIT",
       "dependencies": {
         "is-extglob": "^2.1.1"
@@ -1798,8 +1571,6 @@
     },
     "node_modules/is-number": {
       "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
       "license": "MIT",
       "engines": {
         "node": ">=0.12.0"
@@ -1807,8 +1578,6 @@
     },
     "node_modules/is-path-inside": {
       "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -1816,8 +1585,6 @@
     },
     "node_modules/is-stream": {
       "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -1828,8 +1595,6 @@
     },
     "node_modules/isexe": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
       "license": "ISC"
     },
     "node_modules/js-tokens": {
@@ -1840,8 +1605,6 @@
     },
     "node_modules/js-yaml": {
       "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
       "license": "MIT",
       "dependencies": {
         "argparse": "^2.0.1"
@@ -1850,16 +1613,8 @@
         "js-yaml": "bin/js-yaml.js"
       }
     },
-    "node_modules/jsbn": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
-      "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
-      "license": "MIT"
-    },
     "node_modules/json-buffer": {
       "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
-      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
       "license": "MIT"
     },
     "node_modules/json-parse-even-better-errors": {
@@ -1870,20 +1625,14 @@
     },
     "node_modules/json-schema-traverse": {
       "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
       "license": "MIT"
     },
     "node_modules/json-stable-stringify-without-jsonify": {
       "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
       "license": "MIT"
     },
     "node_modules/keyv": {
       "version": "4.5.4",
-      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
-      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
       "license": "MIT",
       "dependencies": {
         "json-buffer": "3.0.1"
@@ -1891,14 +1640,10 @@
     },
     "node_modules/kuler": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
-      "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
       "license": "MIT"
     },
     "node_modules/levn": {
       "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
-      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
       "license": "MIT",
       "dependencies": {
         "prelude-ls": "^1.2.1",
@@ -1916,8 +1661,6 @@
     },
     "node_modules/locate-path": {
       "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
       "license": "MIT",
       "dependencies": {
         "p-locate": "^5.0.0"
@@ -1931,20 +1674,14 @@
     },
     "node_modules/lodash": {
       "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
       "license": "MIT"
     },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
-      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "license": "MIT"
     },
     "node_modules/logform": {
       "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
-      "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
       "license": "MIT",
       "dependencies": {
         "@colors/colors": "1.6.0",
@@ -1969,8 +1706,6 @@
     },
     "node_modules/merge2": {
       "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
       "license": "MIT",
       "engines": {
         "node": ">= 8"
@@ -1978,8 +1713,6 @@
     },
     "node_modules/micromatch": {
       "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
-      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
       "license": "MIT",
       "dependencies": {
         "braces": "^3.0.3",
@@ -1991,8 +1724,6 @@
     },
     "node_modules/mimic-fn": {
       "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
-      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -2000,8 +1731,6 @@
     },
     "node_modules/minimatch": {
       "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
       "license": "ISC",
       "dependencies": {
         "brace-expansion": "^1.1.7"
@@ -2012,8 +1741,6 @@
     },
     "node_modules/minimist": {
       "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
       "license": "MIT",
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -2027,8 +1754,6 @@
     },
     "node_modules/mkdirp": {
       "version": "0.5.6",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
-      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
       "license": "MIT",
       "dependencies": {
         "minimist": "^1.2.6"
@@ -2039,20 +1764,14 @@
     },
     "node_modules/ms": {
       "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
       "license": "MIT"
     },
     "node_modules/mute-stream": {
       "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
-      "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==",
       "license": "ISC"
     },
     "node_modules/natural-compare": {
       "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
       "license": "MIT"
     },
     "node_modules/netmask": {
@@ -2066,8 +1785,6 @@
     },
     "node_modules/once": {
       "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
       "license": "ISC",
       "dependencies": {
         "wrappy": "1"
@@ -2075,8 +1792,6 @@
     },
     "node_modules/one-time": {
       "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
-      "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
       "license": "MIT",
       "dependencies": {
         "fn.name": "1.x.x"
@@ -2084,8 +1799,6 @@
     },
     "node_modules/onetime": {
       "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
-      "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==",
       "license": "MIT",
       "dependencies": {
         "mimic-fn": "^1.0.0"
@@ -2096,8 +1809,6 @@
     },
     "node_modules/optionator": {
       "version": "0.9.4",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
-      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
       "license": "MIT",
       "dependencies": {
         "deep-is": "^0.1.3",
@@ -2113,8 +1824,6 @@
     },
     "node_modules/os-tmpdir": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
       "license": "MIT",
       "engines": {
         "node": ">=0.10.0"
@@ -2122,8 +1831,6 @@
     },
     "node_modules/p-limit": {
       "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
       "license": "MIT",
       "dependencies": {
         "yocto-queue": "^0.1.0"
@@ -2137,8 +1844,6 @@
     },
     "node_modules/p-locate": {
       "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
       "license": "MIT",
       "dependencies": {
         "p-limit": "^3.0.2"
@@ -2184,8 +1889,6 @@
     },
     "node_modules/parent-module": {
       "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
       "license": "MIT",
       "dependencies": {
         "callsites": "^3.0.0"
@@ -2214,8 +1917,6 @@
     },
     "node_modules/path-exists": {
       "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -2223,8 +1924,6 @@
     },
     "node_modules/path-is-absolute": {
       "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
       "license": "MIT",
       "engines": {
         "node": ">=0.10.0"
@@ -2232,8 +1931,6 @@
     },
     "node_modules/path-key": {
       "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -2253,8 +1950,6 @@
     },
     "node_modules/picomatch": {
       "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
       "license": "MIT",
       "engines": {
         "node": ">=8.6"
@@ -2274,8 +1969,6 @@
     },
     "node_modules/prelude-ls": {
       "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
       "license": "MIT",
       "engines": {
         "node": ">= 0.8.0"
@@ -2327,8 +2020,6 @@
     },
     "node_modules/punycode": {
       "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
       "license": "MIT",
       "engines": {
         "node": ">=6"
@@ -2338,6 +2029,7 @@
       "version": "22.15.0",
       "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.15.0.tgz",
       "integrity": "sha512-XjCY1SiSEi1T7iSYuxS82ft85kwDJUS7wj1Z0eGVXKdtr5g4xnVcbjwxhq5xBnpK/E7x1VZZoJDxpjAOasHT4Q==",
+      "deprecated": "< 24.10.2 is no longer supported",
       "hasInstallScript": true,
       "license": "Apache-2.0",
       "dependencies": {
@@ -2371,8 +2063,6 @@
     },
     "node_modules/queue-microtask": {
       "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
       "funding": [
         {
           "type": "github",
@@ -2391,8 +2081,6 @@
     },
     "node_modules/readable-stream": {
       "version": "3.6.2",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
       "license": "MIT",
       "dependencies": {
         "inherits": "^2.0.3",
@@ -2423,8 +2111,6 @@
     },
     "node_modules/resolve-from": {
       "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -2432,8 +2118,6 @@
     },
     "node_modules/restore-cursor": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
-      "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==",
       "license": "MIT",
       "dependencies": {
         "onetime": "^2.0.0",
@@ -2445,8 +2129,6 @@
     },
     "node_modules/reusify": {
       "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
-      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
       "license": "MIT",
       "engines": {
         "iojs": ">=1.0.0",
@@ -2455,9 +2137,6 @@
     },
     "node_modules/rimraf": {
       "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-      "deprecated": "Rimraf versions prior to v4 are no longer supported",
       "license": "ISC",
       "dependencies": {
         "glob": "^7.1.3"
@@ -2471,8 +2150,6 @@
     },
     "node_modules/run-async": {
       "version": "2.4.1",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
-      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
       "license": "MIT",
       "engines": {
         "node": ">=0.12.0"
@@ -2480,8 +2157,6 @@
     },
     "node_modules/run-parallel": {
       "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
-      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
       "funding": [
         {
           "type": "github",
@@ -2503,8 +2178,6 @@
     },
     "node_modules/rxjs": {
       "version": "6.6.7",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
-      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^1.9.0"
@@ -2515,14 +2188,10 @@
     },
     "node_modules/rxjs/node_modules/tslib": {
       "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
       "license": "0BSD"
     },
     "node_modules/safe-buffer": {
       "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
       "funding": [
         {
           "type": "github",
@@ -2541,8 +2210,6 @@
     },
     "node_modules/safe-stable-stringify": {
       "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
-      "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
       "license": "MIT",
       "engines": {
         "node": ">=10"
@@ -2550,8 +2217,6 @@
     },
     "node_modules/safer-buffer": {
       "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "license": "MIT"
     },
     "node_modules/semver": {
@@ -2568,8 +2233,6 @@
     },
     "node_modules/shebang-command": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
       "license": "MIT",
       "dependencies": {
         "shebang-regex": "^3.0.0"
@@ -2580,8 +2243,6 @@
     },
     "node_modules/shebang-regex": {
       "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -2589,14 +2250,10 @@
     },
     "node_modules/signal-exit": {
       "version": "3.0.7",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
-      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "license": "ISC"
     },
     "node_modules/simple-swizzle": {
       "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
-      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
       "license": "MIT",
       "dependencies": {
         "is-arrayish": "^0.3.1"
@@ -2604,14 +2261,10 @@
     },
     "node_modules/simple-swizzle/node_modules/is-arrayish": {
       "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
-      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
       "license": "MIT"
     },
     "node_modules/slice-ansi": {
       "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
-      "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
       "license": "MIT",
       "dependencies": {
         "ansi-styles": "^3.2.0",
@@ -2624,8 +2277,6 @@
     },
     "node_modules/slice-ansi/node_modules/ansi-styles": {
       "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
       "license": "MIT",
       "dependencies": {
         "color-convert": "^1.9.0"
@@ -2636,8 +2287,6 @@
     },
     "node_modules/slice-ansi/node_modules/color-convert": {
       "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
       "license": "MIT",
       "dependencies": {
         "color-name": "1.1.3"
@@ -2645,8 +2294,6 @@
     },
     "node_modules/slice-ansi/node_modules/color-name": {
       "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
       "license": "MIT"
     },
     "node_modules/smart-buffer": {
@@ -2660,12 +2307,12 @@
       }
     },
     "node_modules/socks": {
-      "version": "2.8.6",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz",
-      "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==",
+      "version": "2.8.7",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
+      "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
       "license": "MIT",
       "dependencies": {
-        "ip-address": "^9.0.5",
+        "ip-address": "^10.0.1",
         "smart-buffer": "^4.2.0"
       },
       "engines": {
@@ -2697,16 +2344,8 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/sprintf-js": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
-      "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
-      "license": "BSD-3-Clause"
-    },
     "node_modules/stack-trace": {
       "version": "0.0.10",
-      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
-      "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
       "license": "MIT",
       "engines": {
         "node": "*"
@@ -2727,8 +2366,6 @@
     },
     "node_modules/string_decoder": {
       "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
-      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
       "license": "MIT",
       "dependencies": {
         "safe-buffer": "~5.2.0"
@@ -2736,8 +2373,6 @@
     },
     "node_modules/string-width": {
       "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-      "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
       "license": "MIT",
       "dependencies": {
         "emoji-regex": "^7.0.1",
@@ -2750,8 +2385,6 @@
     },
     "node_modules/string-width/node_modules/ansi-regex": {
       "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
-      "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
       "license": "MIT",
       "engines": {
         "node": ">=6"
@@ -2759,8 +2392,6 @@
     },
     "node_modules/string-width/node_modules/strip-ansi": {
       "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
       "license": "MIT",
       "dependencies": {
         "ansi-regex": "^4.1.0"
@@ -2771,8 +2402,6 @@
     },
     "node_modules/strip-ansi": {
       "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
       "license": "MIT",
       "dependencies": {
         "ansi-regex": "^5.0.1"
@@ -2783,8 +2412,6 @@
     },
     "node_modules/strip-json-comments": {
       "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -2795,8 +2422,6 @@
     },
     "node_modules/supports-color": {
       "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
       "license": "MIT",
       "dependencies": {
         "has-flag": "^4.0.0"
@@ -2807,8 +2432,6 @@
     },
     "node_modules/table": {
       "version": "5.4.6",
-      "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
-      "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
       "license": "BSD-3-Clause",
       "dependencies": {
         "ajv": "^6.10.2",
@@ -2822,8 +2445,6 @@
     },
     "node_modules/tabtab": {
       "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-3.0.2.tgz",
-      "integrity": "sha512-jANKmUe0sIQc/zTALTBy186PoM/k6aPrh3A7p6AaAfF6WPSbTx1JYeGIGH162btpH+mmVEXln+UxwViZHO2Jhg==",
       "license": "MIT",
       "dependencies": {
         "debug": "^4.0.1",
@@ -2870,26 +2491,18 @@
     },
     "node_modules/text-hex": {
       "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
-      "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
       "license": "MIT"
     },
     "node_modules/text-table": {
       "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
       "license": "MIT"
     },
     "node_modules/through": {
       "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
       "license": "MIT"
     },
     "node_modules/tmp": {
       "version": "0.0.33",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
       "license": "MIT",
       "dependencies": {
         "os-tmpdir": "~1.0.2"
@@ -2900,8 +2513,6 @@
     },
     "node_modules/to-regex-range": {
       "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
       "license": "MIT",
       "dependencies": {
         "is-number": "^7.0.0"
@@ -2912,8 +2523,6 @@
     },
     "node_modules/triple-beam": {
       "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
-      "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
       "license": "MIT",
       "engines": {
         "node": ">= 14.0.0"
@@ -2927,8 +2536,6 @@
     },
     "node_modules/type-check": {
       "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
-      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
       "license": "MIT",
       "dependencies": {
         "prelude-ls": "^1.2.1"
@@ -2939,8 +2546,6 @@
     },
     "node_modules/type-fest": {
       "version": "0.20.2",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
       "license": "(MIT OR CC0-1.0)",
       "engines": {
         "node": ">=10"
@@ -2951,8 +2556,6 @@
     },
     "node_modules/typescript": {
       "version": "5.8.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
-      "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
       "license": "Apache-2.0",
       "bin": {
         "tsc": "bin/tsc",
@@ -2974,8 +2577,6 @@
     },
     "node_modules/untildify": {
       "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz",
-      "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==",
       "license": "MIT",
       "engines": {
         "node": ">=4"
@@ -2983,8 +2584,6 @@
     },
     "node_modules/uri-js": {
       "version": "4.4.1",
-      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
-      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
       "license": "BSD-2-Clause",
       "dependencies": {
         "punycode": "^2.1.0"
@@ -2998,14 +2597,10 @@
     },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
       "license": "MIT"
     },
     "node_modules/which": {
       "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
       "license": "ISC",
       "dependencies": {
         "isexe": "^2.0.0"
@@ -3019,8 +2614,6 @@
     },
     "node_modules/winston": {
       "version": "3.17.0",
-      "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz",
-      "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
       "license": "MIT",
       "dependencies": {
         "@colors/colors": "^1.6.0",
@@ -3041,8 +2634,6 @@
     },
     "node_modules/winston-transport": {
       "version": "4.9.0",
-      "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
-      "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
       "license": "MIT",
       "dependencies": {
         "logform": "^2.7.0",
@@ -3055,8 +2646,6 @@
     },
     "node_modules/word-wrap": {
       "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
-      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
       "license": "MIT",
       "engines": {
         "node": ">=0.10.0"
@@ -3064,8 +2653,6 @@
     },
     "node_modules/wrap-ansi": {
       "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
       "license": "MIT",
       "dependencies": {
         "ansi-styles": "^4.0.0",
@@ -3078,14 +2665,10 @@
     },
     "node_modules/wrap-ansi/node_modules/emoji-regex": {
       "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "license": "MIT"
     },
     "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
       "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -3093,8 +2676,6 @@
     },
     "node_modules/wrap-ansi/node_modules/string-width": {
       "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
       "license": "MIT",
       "dependencies": {
         "emoji-regex": "^8.0.0",
@@ -3107,8 +2688,6 @@
     },
     "node_modules/wrappy": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
       "license": "ISC"
     },
     "node_modules/ws": {
@@ -3209,8 +2788,6 @@
     },
     "node_modules/yocto-queue": {
       "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
-      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
       "license": "MIT",
       "engines": {
         "node": ">=10"
diff --git a/package.json b/package.json
index 04f4c501d1f..976d6303634 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "dependencies": {
-    "browser-ui-test": "^0.21.3",
+    "browser-ui-test": "^0.22.0",
     "es-check": "^6.2.1",
     "eslint": "^8.57.1",
     "eslint-js": "github:eslint/js",
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 1535d087033..fe832652d25 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -269,14 +269,14 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "filetime"
-version = "0.2.25"
+version = "0.2.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
+checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
 dependencies = [
  "cfg-if",
  "libc",
  "libredox",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -322,11 +322,11 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "home"
-version = "0.5.9"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -364,12 +364,12 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "junction"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16"
+checksum = "c52f6e1bf39a7894f618c9d378904a11dbd7e10fe3ec20d1173600e79b1408d8"
 dependencies = [
  "scopeguard",
- "windows-sys 0.52.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -434,6 +434,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
+name = "normpath"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
 name = "ntapi"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -497,12 +506,13 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "opener"
-version = "0.5.2"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005"
+checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223"
 dependencies = [
  "bstr",
- "winapi",
+ "normpath",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -757,15 +767,15 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.19.0"
+version = "3.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600"
+checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e"
 dependencies = [
  "fastrand",
  "getrandom",
  "once_cell",
  "rustix",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -929,11 +939,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.9"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22"
 dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -1045,20 +1055,20 @@ dependencies = [
 
 [[package]]
 name = "windows-sys"
-version = "0.52.0"
+version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
 name = "windows-sys"
-version = "0.59.0"
+version = "0.60.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.53.2",
 ]
 
 [[package]]
@@ -1067,14 +1077,30 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 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",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "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]]
+name = "windows-targets"
+version = "0.53.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
+dependencies = [
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
 ]
 
 [[package]]
@@ -1084,48 +1110,96 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[package]]
 name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[package]]
 name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[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_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[package]]
 name = "windows_x86_64_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[package]]
 name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
 name = "wit-bindgen-rt"
 version = "0.39.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index c7175584465..9a76a7dda2a 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -42,7 +42,7 @@ home = "0.5"
 ignore = "0.4"
 libc = "0.2"
 object = { version = "0.36.3", default-features = false, features = ["archive", "coff", "read_core", "std", "unaligned"] }
-opener = "0.5"
+opener = "0.8"
 semver = "1.0"
 serde = "1.0"
 # Directly use serde_derive rather than through the derive feature of serde to allow building both
@@ -67,7 +67,7 @@ tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter
 tempfile = { version = "3.15.0", optional = true }
 
 [target.'cfg(windows)'.dependencies.junction]
-version = "1.0.0"
+version = "1.3.0"
 
 [target.'cfg(windows)'.dependencies.windows]
 version = "0.61"
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 82c05092dfa..03caa764ccf 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -76,7 +76,7 @@ check-aux:
 		library/std \
 		$(BOOTSTRAP_ARGS) \
 		-- \
-		--skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal::
+		--skip fs:: --skip net:: --skip process:: --skip sys::
 	# Also test some very target-specific modules on other targets
 	# (making sure to cover an i686 target as well).
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index a604e7c0585..043457f64e5 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -389,7 +389,7 @@ impl Step for Rustc {
 
 /// Represents a compiler that can check something.
 ///
-/// If the compiler was created for `Mode::ToolRustc` or `Mode::Codegen`, it will also contain
+/// If the compiler was created for `Mode::ToolRustcPrivate` or `Mode::Codegen`, it will also contain
 /// .rmeta artifacts from rustc that was already checked using `build_compiler`.
 ///
 /// All steps that use this struct in a "general way" (i.e. they don't know exactly what kind of
@@ -469,7 +469,7 @@ pub fn prepare_compiler_for_check(
                 build_compiler
             }
         }
-        Mode::ToolRustc | Mode::Codegen => {
+        Mode::ToolRustcPrivate | Mode::Codegen => {
             // Check Rustc to produce the required rmeta artifacts for rustc_private, and then
             // return the build compiler that was used to check rustc.
             // We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass
@@ -767,19 +767,22 @@ fn run_tool_check_step(
 tool_check_step!(Rustdoc {
     path: "src/tools/rustdoc",
     alt_path: "src/librustdoc",
-    mode: |_builder| Mode::ToolRustc
+    mode: |_builder| Mode::ToolRustcPrivate
 });
 // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
 // of a submodule. Since the SourceType only drives the deny-warnings
 // behavior, treat it as in-tree so that any new warnings in clippy will be
 // rejected.
-tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustc });
-tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustc });
-tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: |_builder| Mode::ToolRustc });
-tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustc });
+tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustcPrivate });
+tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustcPrivate });
+tool_check_step!(CargoMiri {
+    path: "src/tools/miri/cargo-miri",
+    mode: |_builder| Mode::ToolRustcPrivate
+});
+tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustcPrivate });
 tool_check_step!(RustAnalyzer {
     path: "src/tools/rust-analyzer",
-    mode: |_builder| Mode::ToolRustc,
+    mode: |_builder| Mode::ToolRustcPrivate,
     allow_features: tool::RustAnalyzer::ALLOW_FEATURES,
     enable_features: ["in-rust-tree"],
 });
@@ -836,3 +839,9 @@ tool_check_step!(Linkchecker {
     mode: |_builder| Mode::ToolBootstrap,
     default: false
 });
+
+tool_check_step!(BumpStage0 {
+    path: "src/tools/bump-stage0",
+    mode: |_builder| Mode::ToolBootstrap,
+    default: false
+});
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 05f8b240291..2083c675e1f 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -366,8 +366,13 @@ impl Step for CodegenGcc {
         );
         self.build_compiler.configure_cargo(&mut cargo);
 
-        let _guard =
-            builder.msg(Kind::Clippy, "rustc_codegen_gcc", Mode::ToolRustc, build_compiler, target);
+        let _guard = builder.msg(
+            Kind::Clippy,
+            "rustc_codegen_gcc",
+            Mode::ToolRustcPrivate,
+            build_compiler,
+            target,
+        );
 
         let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Codegen, target))
             .with_prefix("rustc_codegen_gcc-check");
@@ -478,8 +483,8 @@ lint_any!(
     Bootstrap, "src/bootstrap", "bootstrap", Mode::ToolTarget;
     BuildHelper, "src/build_helper", "build_helper", Mode::ToolTarget;
     BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolTarget;
-    CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", Mode::ToolRustc;
-    Clippy, "src/tools/clippy", "clippy", Mode::ToolRustc;
+    CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", Mode::ToolRustcPrivate;
+    Clippy, "src/tools/clippy", "clippy", Mode::ToolRustcPrivate;
     CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata", Mode::ToolTarget;
     Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTarget;
     CoverageDump, "src/tools/coverage-dump", "coverage-dump", Mode::ToolTarget;
@@ -487,14 +492,14 @@ lint_any!(
     Jsondoclint, "src/tools/jsondoclint", "jsondoclint", Mode::ToolTarget;
     LintDocs, "src/tools/lint-docs", "lint-docs", Mode::ToolTarget;
     LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker", Mode::ToolTarget;
-    Miri, "src/tools/miri", "miri", Mode::ToolRustc;
+    Miri, "src/tools/miri", "miri", Mode::ToolRustcPrivate;
     MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools", Mode::ToolTarget;
     OptDist, "src/tools/opt-dist", "opt-dist", Mode::ToolTarget;
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolTarget;
     RemoteTestServer, "src/tools/remote-test-server", "remote-test-server", Mode::ToolTarget;
-    RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer", Mode::ToolRustc;
-    Rustdoc, "src/librustdoc", "clippy", Mode::ToolRustc;
-    Rustfmt, "src/tools/rustfmt", "rustfmt", Mode::ToolRustc;
+    RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer", Mode::ToolRustcPrivate;
+    Rustdoc, "src/librustdoc", "clippy", Mode::ToolRustcPrivate;
+    Rustfmt, "src/tools/rustfmt", "rustfmt", Mode::ToolRustcPrivate;
     RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::ToolTarget;
     Tidy, "src/tools/tidy", "tidy", Mode::ToolTarget;
     TestFloatParse, "src/tools/test-float-parse", "test-float-parse", Mode::ToolStd;
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index f113dd7683d..a5f0718bc01 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -88,6 +88,7 @@ impl Step for Docs {
         tarball.set_product_name("Rust Documentation");
         tarball.add_bulk_dir(builder.doc_out(host), dest);
         tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, FileType::Regular);
+        tarball.add_file(builder.src.join("src/doc/sitemap.txt"), dest, FileType::Regular);
         Some(tarball.generate())
     }
 
@@ -823,6 +824,18 @@ pub struct RustcDev {
     target: TargetSelection,
 }
 
+impl RustcDev {
+    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
+        Self {
+            // We currently always ship a stage 2 rustc-dev component, so we build it with the
+            // stage 1 compiler. This might change in the future.
+            // The precise stage used here is important, so we hard-code it.
+            build_compiler: builder.compiler(1, builder.config.host_target),
+            target,
+        }
+    }
+}
+
 impl Step for RustcDev {
     type Output = Option<GeneratedTarball>;
     const DEFAULT: bool = true;
@@ -833,13 +846,7 @@ impl Step for RustcDev {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(RustcDev {
-            // We currently always ship a stage 2 rustc-dev component, so we build it with the
-            // stage 1 compiler. This might change in the future.
-            // The precise stage used here is important, so we hard-code it.
-            build_compiler: run.builder.compiler(1, run.builder.config.host_target),
-            target: run.target,
-        });
+        run.builder.ensure(RustcDev::new(run.builder, run.target));
     }
 
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 0789eefa894..7865b685659 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -575,6 +575,31 @@ impl Step for SharedAssets {
             FileType::Regular,
         );
 
+        builder.copy_link(
+            &builder
+                .src
+                .join("src")
+                .join("librustdoc")
+                .join("html")
+                .join("static")
+                .join("images")
+                .join("favicon.svg"),
+            &out.join("favicon.svg"),
+            FileType::Regular,
+        );
+        builder.copy_link(
+            &builder
+                .src
+                .join("src")
+                .join("librustdoc")
+                .join("html")
+                .join("static")
+                .join("images")
+                .join("favicon-32x32.png"),
+            &out.join("favicon-32x32.png"),
+            FileType::Regular,
+        );
+
         SharedAssetsPaths { version_info }
     }
 }
@@ -965,9 +990,11 @@ macro_rules! tool_doc {
     (
         $tool: ident,
         $path: literal,
-        $(rustc_private_tool = $rustc_private_tool:literal, )?
-        $(is_library = $is_library:expr,)?
-        $(crates = $crates:expr)?
+        mode = $mode:expr
+        $(, is_library = $is_library:expr )?
+        $(, crates = $crates:expr )?
+        // Subset of nightly features that are allowed to be used when documenting
+        $(, allow_features: $allow_features:expr )?
        ) => {
         #[derive(Debug, Clone, Hash, PartialEq, Eq)]
         pub struct $tool {
@@ -988,20 +1015,29 @@ macro_rules! tool_doc {
 
             fn make_run(run: RunConfig<'_>) {
                 let target = run.target;
-                let (build_compiler, mode) = if true $(&& $rustc_private_tool)? {
-                    // Rustdoc needs the rustc sysroot available to build.
-                    let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, target);
-
-                    // Build rustc docs so that we generate relative links.
-                    run.builder.ensure(Rustc::from_build_compiler(run.builder, compilers.build_compiler(), target));
-
-                    (compilers.build_compiler(), Mode::ToolRustc)
-                } else {
-                    // bootstrap/host tools have to be documented with the stage 0 compiler
-                    (prepare_doc_compiler(run.builder, run.builder.host_target, 1), Mode::ToolBootstrap)
+                let build_compiler = match $mode {
+                    Mode::ToolRustcPrivate => {
+                        // Rustdoc needs the rustc sysroot available to build.
+                        let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, target);
+
+                        // Build rustc docs so that we generate relative links.
+                        run.builder.ensure(Rustc::from_build_compiler(run.builder, compilers.build_compiler(), target));
+                        compilers.build_compiler()
+                    }
+                    Mode::ToolBootstrap => {
+                        // bootstrap/host tools should be documented with the stage 0 compiler
+                        prepare_doc_compiler(run.builder, run.builder.host_target, 1)
+                    }
+                    Mode::ToolTarget => {
+                        // target tools should be documented with the in-tree compiler
+                        prepare_doc_compiler(run.builder, run.builder.host_target, run.builder.top_stage)
+                    }
+                    _ => {
+                        panic!("Unexpected tool mode for documenting: {:?}", $mode);
+                    }
                 };
 
-                run.builder.ensure($tool { build_compiler, mode, target });
+                run.builder.ensure($tool { build_compiler, mode: $mode, target });
             }
 
             /// Generates documentation for a tool.
@@ -1032,6 +1068,15 @@ macro_rules! tool_doc {
                     source_type,
                     &[],
                 );
+                let allow_features = {
+                    let mut _value = "";
+                    $( _value = $allow_features; )?
+                    _value
+                };
+
+                if !allow_features.is_empty() {
+                    cargo.allow_features(allow_features);
+                }
 
                 cargo.arg("-Zskip-rustdoc-fingerprint");
                 // Only include compiler crates, no dependencies of those, such as `libc`.
@@ -1087,18 +1132,33 @@ macro_rules! tool_doc {
 tool_doc!(
     BuildHelper,
     "src/build_helper",
-    rustc_private_tool = false,
+    mode = Mode::ToolBootstrap,
     is_library = true,
     crates = ["build_helper"]
 );
-tool_doc!(Rustdoc, "src/tools/rustdoc", crates = ["rustdoc", "rustdoc-json-types"]);
-tool_doc!(Rustfmt, "src/tools/rustfmt", crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]);
-tool_doc!(Clippy, "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]);
-tool_doc!(Miri, "src/tools/miri", crates = ["miri"]);
+tool_doc!(
+    Rustdoc,
+    "src/tools/rustdoc",
+    mode = Mode::ToolRustcPrivate,
+    crates = ["rustdoc", "rustdoc-json-types"]
+);
+tool_doc!(
+    Rustfmt,
+    "src/tools/rustfmt",
+    mode = Mode::ToolRustcPrivate,
+    crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]
+);
+tool_doc!(
+    Clippy,
+    "src/tools/clippy",
+    mode = Mode::ToolRustcPrivate,
+    crates = ["clippy_config", "clippy_utils"]
+);
+tool_doc!(Miri, "src/tools/miri", mode = Mode::ToolRustcPrivate, crates = ["miri"]);
 tool_doc!(
     Cargo,
     "src/tools/cargo",
-    rustc_private_tool = false,
+    mode = Mode::ToolTarget,
     crates = [
         "cargo",
         "cargo-credential",
@@ -1110,27 +1170,30 @@ tool_doc!(
         "crates-io",
         "mdman",
         "rustfix",
-    ]
+    ],
+    // Required because of the im-rc dependency of Cargo, which automatically opts into the
+    // "specialization" feature in its build script when it detects a nightly toolchain.
+    allow_features: "specialization"
 );
-tool_doc!(Tidy, "src/tools/tidy", rustc_private_tool = false, crates = ["tidy"]);
+tool_doc!(Tidy, "src/tools/tidy", mode = Mode::ToolBootstrap, crates = ["tidy"]);
 tool_doc!(
     Bootstrap,
     "src/bootstrap",
-    rustc_private_tool = false,
+    mode = Mode::ToolBootstrap,
     is_library = true,
     crates = ["bootstrap"]
 );
 tool_doc!(
     RunMakeSupport,
     "src/tools/run-make-support",
-    rustc_private_tool = false,
+    mode = Mode::ToolBootstrap,
     is_library = true,
     crates = ["run_make_support"]
 );
 tool_doc!(
     Compiletest,
     "src/tools/compiletest",
-    rustc_private_tool = false,
+    mode = Mode::ToolBootstrap,
     is_library = true,
     crates = ["compiletest"]
 );
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index d47c1495838..83ed7430c39 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -205,6 +205,7 @@ pub(crate) fn is_ci_llvm_available_for_target(
         // tier 1
         ("aarch64-unknown-linux-gnu", false),
         ("aarch64-apple-darwin", false),
+        ("aarch64-pc-windows-msvc", false),
         ("i686-pc-windows-gnu", false),
         ("i686-pc-windows-msvc", false),
         ("i686-unknown-linux-gnu", false),
@@ -213,7 +214,6 @@ pub(crate) fn is_ci_llvm_available_for_target(
         ("x86_64-pc-windows-gnu", true),
         ("x86_64-pc-windows-msvc", true),
         // tier 2 with host tools
-        ("aarch64-pc-windows-msvc", false),
         ("aarch64-unknown-linux-musl", false),
         ("arm-unknown-linux-gnueabi", false),
         ("arm-unknown-linux-gnueabihf", false),
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index d9de6b7ef96..9f7248b80f7 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -161,7 +161,7 @@ impl Step for Miri {
         let mut miri = tool::prepare_tool_cargo(
             builder,
             compilers.build_compiler(),
-            Mode::ToolRustc,
+            Mode::ToolRustcPrivate,
             host,
             Kind::Run,
             "src/tools/miri",
@@ -487,7 +487,7 @@ impl Step for Rustfmt {
         let mut rustfmt = tool::prepare_tool_cargo(
             builder,
             rustfmt_build.build_compiler,
-            Mode::ToolRustc,
+            Mode::ToolRustcPrivate,
             host,
             Kind::Run,
             "src/tools/rustfmt",
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index ee2cbe9385e..4f839bdf7b8 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -455,7 +455,7 @@ impl Step for RustAnalyzer {
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             self.compilers.build_compiler(),
-            Mode::ToolRustc,
+            Mode::ToolRustcPrivate,
             host,
             Kind::Test,
             crate_path,
@@ -518,7 +518,7 @@ impl Step for Rustfmt {
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             build_compiler,
-            Mode::ToolRustc,
+            Mode::ToolRustcPrivate,
             target,
             Kind::Test,
             "src/tools/rustfmt",
@@ -571,7 +571,8 @@ impl Miri {
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
 
         let mut cargo = BootstrapCommand::from(cargo);
-        let _guard = builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustc, compiler, target);
+        let _guard =
+            builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustcPrivate, compiler, target);
         cargo.run(builder);
 
         // # Determine where Miri put its sysroot.
@@ -648,7 +649,7 @@ impl Step for Miri {
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             miri.build_compiler,
-            Mode::ToolRustc,
+            Mode::ToolRustcPrivate,
             host,
             Kind::Test,
             "src/tools/miri",
@@ -861,7 +862,7 @@ impl Step for Clippy {
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             build_compiler,
-            Mode::ToolRustc,
+            Mode::ToolRustcPrivate,
             target,
             Kind::Test,
             "src/tools/clippy",
@@ -872,7 +873,7 @@ impl Step for Clippy {
         cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler));
         cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler));
         let host_libs =
-            builder.stage_out(build_compiler, Mode::ToolRustc).join(builder.cargo_dir());
+            builder.stage_out(build_compiler, Mode::ToolRustcPrivate).join(builder.cargo_dir());
         cargo.env("HOST_LIBS", host_libs);
 
         // Build the standard library that the tests can use.
@@ -1521,6 +1522,12 @@ test!(Pretty {
 });
 
 test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true });
+test!(RunMakeCargo {
+    path: "tests/run-make-cargo",
+    mode: "run-make",
+    suite: "run-make-cargo",
+    default: true
+});
 
 test!(AssemblyLlvm {
     path: "tests/assembly-llvm",
@@ -1772,7 +1779,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
                 target,
             });
         }
-        if suite == "run-make" {
+        if mode == "run-make" {
             builder.tool_exe(Tool::RunMakeSupport);
         }
 
@@ -1815,25 +1822,41 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
 
         let is_rustdoc = suite == "rustdoc-ui" || suite == "rustdoc-js";
 
+        // There are (potentially) 2 `cargo`s to consider:
+        //
+        // - A "bootstrap" cargo, which is the same cargo used to build bootstrap itself, and is
+        //   used to build the `run-make` test recipes and the `run-make-support` test library. All
+        //   of these may not use unstable rustc/cargo features.
+        // - An in-tree cargo, which should be considered as under test. The `run-make-cargo` test
+        //   suite is intended to support the use case of testing the "toolchain" (that is, at the
+        //   minimum the interaction between in-tree cargo + rustc) together.
+        //
+        // For build time and iteration purposes, we partition `run-make` tests which needs an
+        // in-tree cargo (a smaller subset) versus `run-make` tests that do not into two test
+        // suites, `run-make` and `run-make-cargo`. That way, contributors who do not need to run
+        // the `run-make` tests that need in-tree cargo do not need to spend time building in-tree
+        // cargo.
         if mode == "run-make" {
-            let cargo_path = if test_compiler.stage == 0 {
-                // If we're using `--stage 0`, we should provide the bootstrap cargo.
-                builder.initial_cargo.clone()
-            } else {
-                builder
-                    .ensure(tool::Cargo::from_build_compiler(
-                        builder.compiler(test_compiler.stage - 1, test_compiler.host),
-                        test_compiler.host,
-                    ))
-                    .tool_path
-            };
-
-            cmd.arg("--cargo-path").arg(cargo_path);
-
             // We need to pass the compiler that was used to compile run-make-support,
             // because we have to use the same compiler to compile rmake.rs recipes.
             let stage0_rustc_path = builder.compiler(0, test_compiler.host);
             cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path));
+
+            if suite == "run-make-cargo" {
+                let cargo_path = if test_compiler.stage == 0 {
+                    // If we're using `--stage 0`, we should provide the bootstrap cargo.
+                    builder.initial_cargo.clone()
+                } else {
+                    builder
+                        .ensure(tool::Cargo::from_build_compiler(
+                            builder.compiler(test_compiler.stage - 1, test_compiler.host),
+                            test_compiler.host,
+                        ))
+                        .tool_path
+                };
+
+                cmd.arg("--cargo-path").arg(cargo_path);
+            }
         }
 
         // Avoid depending on rustdoc when we don't need it.
@@ -2411,7 +2434,7 @@ impl BookTest {
         let libs = if !self.dependencies.is_empty() {
             let mut lib_paths = vec![];
             for dep in self.dependencies {
-                let mode = Mode::ToolRustc;
+                let mode = Mode::ToolRustcPrivate;
                 let target = builder.config.host_target;
                 let cargo = tool::prepare_tool_cargo(
                     builder,
@@ -2996,7 +3019,7 @@ impl Step for CrateRustdoc {
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
-            Mode::ToolRustc,
+            Mode::ToolRustcPrivate,
             target,
             builder.kind,
             "src/tools/rustdoc",
@@ -3182,6 +3205,7 @@ impl Step for Distcheck {
     ///   check steps from those sources.
     /// - Check that selected dist components (`rust-src` only at the moment) at least have expected
     ///   directory shape and crate manifests that cargo can generate a lockfile from.
+    /// - Check that we can run `cargo metadata` on the workspace in the `rustc-dev` component
     ///
     /// FIXME(#136822): dist components are under-tested.
     fn run(self, builder: &Builder<'_>) {
@@ -3189,61 +3213,91 @@ impl Step for Distcheck {
         // local source code, built artifacts or configuration by accident
         let root_dir = std::env::temp_dir().join("distcheck");
 
-        // Check that we can build some basic things from the plain source tarball
-        builder.info("Distcheck plain source tarball");
-        let plain_src_tarball = builder.ensure(dist::PlainSourceTarball);
-        let plain_src_dir = root_dir.join("distcheck-plain-src");
-        builder.clear_dir(&plain_src_dir);
-
-        let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS")
-            .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>())
-            .unwrap_or_default();
-
-        command("tar")
-            .arg("-xf")
-            .arg(plain_src_tarball.tarball())
-            .arg("--strip-components=1")
-            .current_dir(&plain_src_dir)
-            .run(builder);
-        command("./configure")
-            .arg("--set")
-            .arg("rust.omit-git-hash=false")
-            .args(&configure_args)
-            .arg("--enable-vendor")
-            .current_dir(&plain_src_dir)
-            .run(builder);
-        command(helpers::make(&builder.config.host_target.triple))
-            .arg("check")
-            // Do not run the build as if we were in CI, otherwise git would be assumed to be
-            // present, but we build from a tarball here
-            .env("GITHUB_ACTIONS", "0")
-            .current_dir(&plain_src_dir)
-            .run(builder);
-
-        // Now make sure that rust-src has all of libstd's dependencies
-        builder.info("Distcheck rust-src");
-        let src_tarball = builder.ensure(dist::Src);
-        let src_dir = root_dir.join("distcheck-src");
-        builder.clear_dir(&src_dir);
-
-        command("tar")
-            .arg("-xf")
-            .arg(src_tarball.tarball())
-            .arg("--strip-components=1")
-            .current_dir(&src_dir)
-            .run(builder);
-
-        let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
-        command(&builder.initial_cargo)
-            // Will read the libstd Cargo.toml
-            // which uses the unstable `public-dependency` feature.
-            .env("RUSTC_BOOTSTRAP", "1")
-            .arg("generate-lockfile")
-            .arg("--manifest-path")
-            .arg(&toml)
-            .current_dir(&src_dir)
-            .run(builder);
-    }
+        distcheck_plain_source_tarball(builder, &root_dir.join("distcheck-rustc-src"));
+        distcheck_rust_src(builder, &root_dir.join("distcheck-rust-src"));
+        distcheck_rustc_dev(builder, &root_dir.join("distcheck-rustc-dev"));
+    }
+}
+
+/// Check that we can build some basic things from the plain source tarball
+fn distcheck_plain_source_tarball(builder: &Builder<'_>, plain_src_dir: &Path) {
+    builder.info("Distcheck plain source tarball");
+    let plain_src_tarball = builder.ensure(dist::PlainSourceTarball);
+    builder.clear_dir(plain_src_dir);
+
+    let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS")
+        .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>())
+        .unwrap_or_default();
+
+    command("tar")
+        .arg("-xf")
+        .arg(plain_src_tarball.tarball())
+        .arg("--strip-components=1")
+        .current_dir(plain_src_dir)
+        .run(builder);
+    command("./configure")
+        .arg("--set")
+        .arg("rust.omit-git-hash=false")
+        .args(&configure_args)
+        .arg("--enable-vendor")
+        .current_dir(plain_src_dir)
+        .run(builder);
+    command(helpers::make(&builder.config.host_target.triple))
+        .arg("check")
+        // Do not run the build as if we were in CI, otherwise git would be assumed to be
+        // present, but we build from a tarball here
+        .env("GITHUB_ACTIONS", "0")
+        .current_dir(plain_src_dir)
+        .run(builder);
+}
+
+/// Check that rust-src has all of libstd's dependencies
+fn distcheck_rust_src(builder: &Builder<'_>, src_dir: &Path) {
+    builder.info("Distcheck rust-src");
+    let src_tarball = builder.ensure(dist::Src);
+    builder.clear_dir(src_dir);
+
+    command("tar")
+        .arg("-xf")
+        .arg(src_tarball.tarball())
+        .arg("--strip-components=1")
+        .current_dir(src_dir)
+        .run(builder);
+
+    let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
+    command(&builder.initial_cargo)
+        // Will read the libstd Cargo.toml
+        // which uses the unstable `public-dependency` feature.
+        .env("RUSTC_BOOTSTRAP", "1")
+        .arg("generate-lockfile")
+        .arg("--manifest-path")
+        .arg(&toml)
+        .current_dir(src_dir)
+        .run(builder);
+}
+
+/// Check that rustc-dev's compiler crate source code can be loaded with `cargo metadata`
+fn distcheck_rustc_dev(builder: &Builder<'_>, dir: &Path) {
+    builder.info("Distcheck rustc-dev");
+    let tarball = builder.ensure(dist::RustcDev::new(builder, builder.host_target)).unwrap();
+    builder.clear_dir(dir);
+
+    command("tar")
+        .arg("-xf")
+        .arg(tarball.tarball())
+        .arg("--strip-components=1")
+        .current_dir(dir)
+        .run(builder);
+
+    command(&builder.initial_cargo)
+        .arg("metadata")
+        .arg("--manifest-path")
+        .arg("rustc-dev/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml")
+        .env("RUSTC_BOOTSTRAP", "1")
+        // We might not have a globally available `rustc` binary on CI
+        .env("RUSTC", &builder.initial_rustc)
+        .current_dir(dir)
+        .run(builder);
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -3294,9 +3348,7 @@ impl Step for Bootstrap {
             .env("INSTA_WORKSPACE_ROOT", &builder.src)
             .env("RUSTC_BOOTSTRAP", "1");
 
-        // bootstrap tests are racy on directory creation so just run them one at a time.
-        // Since there's not many this shouldn't be a problem.
-        run_cargo_test(cargo, &["--test-threads=1"], &[], None, host, builder);
+        run_cargo_test(cargo, &[], &[], None, host, builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 65c4c499086..6870bf3eddc 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -82,7 +82,7 @@ impl Step for ToolBuild {
         let path = self.path;
 
         match self.mode {
-            Mode::ToolRustc => {
+            Mode::ToolRustcPrivate => {
                 // FIXME: remove this, it's only needed for download-rustc...
                 if !self.build_compiler.is_forced_compiler() && builder.download_rustc() {
                     builder.std(self.build_compiler, self.build_compiler.host);
@@ -121,9 +121,11 @@ impl Step for ToolBuild {
             cargo.env("RUSTC_WRAPPER", ccache);
         }
 
-        // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer)
+        // RustcPrivate tools (miri, clippy, rustfmt, rust-analyzer) and cargo
         // could use the additional optimizations.
-        if self.mode == Mode::ToolRustc && is_lto_stage(&self.build_compiler) {
+        if is_lto_stage(&self.build_compiler)
+            && (self.mode == Mode::ToolRustcPrivate || self.path == "src/tools/cargo")
+        {
             let lto = match builder.config.rust_lto {
                 RustcLto::Off => Some("off"),
                 RustcLto::Thin => Some("thin"),
@@ -607,7 +609,7 @@ impl Step for ErrorIndex {
             build_compiler: self.compilers.build_compiler,
             target: self.compilers.target(),
             tool: "error_index_generator",
-            mode: Mode::ToolRustc,
+            mode: Mode::ToolRustcPrivate,
             path: "src/tools/error_index_generator",
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
@@ -671,7 +673,7 @@ impl Step for RemoteTestServer {
 /// Represents `Rustdoc` that either comes from the external stage0 sysroot or that is built
 /// locally.
 /// Rustdoc is special, because it both essentially corresponds to a `Compiler` (that can be
-/// externally provided), but also to a `ToolRustc` tool.
+/// externally provided), but also to a `ToolRustcPrivate` tool.
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Rustdoc {
     /// If the stage of `target_compiler` is `0`, then rustdoc is externally provided.
@@ -759,7 +761,7 @@ impl Step for Rustdoc {
                 // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
                 // rustdoc a different name.
                 tool: "rustdoc_tool_binary",
-                mode: Mode::ToolRustc,
+                mode: Mode::ToolRustcPrivate,
                 path: "src/tools/rustdoc",
                 source_type: SourceType::InTree,
                 extra_features,
@@ -1048,7 +1050,7 @@ impl Step for RustAnalyzer {
             build_compiler,
             target,
             tool: "rust-analyzer",
-            mode: Mode::ToolRustc,
+            mode: Mode::ToolRustcPrivate,
             path: "src/tools/rust-analyzer",
             extra_features: vec!["in-rust-tree".to_owned()],
             source_type: SourceType::InTree,
@@ -1105,7 +1107,7 @@ impl Step for RustAnalyzerProcMacroSrv {
             build_compiler: self.compilers.build_compiler,
             target: self.compilers.target(),
             tool: "rust-analyzer-proc-macro-srv",
-            mode: Mode::ToolRustc,
+            mode: Mode::ToolRustcPrivate,
             path: "src/tools/rust-analyzer/crates/proc-macro-srv-cli",
             extra_features: vec!["in-rust-tree".to_owned()],
             source_type: SourceType::InTree,
@@ -1352,7 +1354,7 @@ impl RustcPrivateCompilers {
     }
 }
 
-/// Creates a step that builds an extended `Mode::ToolRustc` tool
+/// Creates a step that builds an extended `Mode::ToolRustcPrivate` tool
 /// and installs it into the sysroot of a corresponding compiler.
 macro_rules! tool_rustc_extended {
     (
@@ -1466,7 +1468,7 @@ fn build_extended_rustc_tool(
         build_compiler,
         target,
         tool: tool_name,
-        mode: Mode::ToolRustc,
+        mode: Mode::ToolRustcPrivate,
         path,
         extra_features,
         source_type: SourceType::InTree,
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index cdf6fe573e5..924bb4adb42 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -533,7 +533,7 @@ impl Builder<'_> {
         if cmd_kind == Kind::Doc {
             let my_out = match mode {
                 // This is the intended out directory for compiler documentation.
-                Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap => {
+                Mode::Rustc | Mode::ToolRustcPrivate | Mode::ToolBootstrap | Mode::ToolTarget => {
                     self.compiler_doc_out(target)
                 }
                 Mode::Std => {
@@ -583,7 +583,7 @@ impl Builder<'_> {
 
         // We synthetically interpret a stage0 compiler used to build tools as a
         // "raw" compiler in that it's the exact snapshot we download. For things like
-        // ToolRustc, we would have to use the artificial stage0-sysroot compiler instead.
+        // ToolRustcPrivate, we would have to use the artificial stage0-sysroot compiler instead.
         let use_snapshot =
             mode == Mode::ToolBootstrap || (mode == Mode::ToolTarget && build_compiler_stage == 0);
         assert!(!use_snapshot || build_compiler_stage == 0 || self.local_rebuild);
@@ -643,7 +643,8 @@ impl Builder<'_> {
         // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
         // library unnecessary. This can be removed when windows-rs enables raw-dylib
         // unconditionally.
-        if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap | Mode::ToolTarget = mode {
+        if let Mode::Rustc | Mode::ToolRustcPrivate | Mode::ToolBootstrap | Mode::ToolTarget = mode
+        {
             rustflags.arg("--cfg=windows_raw_dylib");
         }
 
@@ -657,7 +658,7 @@ impl Builder<'_> {
         // - rust-analyzer, due to the rowan crate
         // so we exclude an entire category of steps here due to lack of fine-grained control over
         // rustflags.
-        if self.config.rust_randomize_layout && mode != Mode::ToolRustc {
+        if self.config.rust_randomize_layout && mode != Mode::ToolRustcPrivate {
             rustflags.arg("-Zrandomize-layout");
         }
 
@@ -717,7 +718,7 @@ impl Builder<'_> {
 
         match mode {
             Mode::Std | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {}
-            Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
+            Mode::Rustc | Mode::Codegen | Mode::ToolRustcPrivate => {
                 // Build proc macros both for the host and the target unless proc-macros are not
                 // supported by the target.
                 if target != compiler.host && cmd_kind != Kind::Check {
@@ -778,7 +779,7 @@ impl Builder<'_> {
                 "binary-dep-depinfo,proc_macro_span,proc_macro_span_shrink,proc_macro_diagnostic"
                     .to_string()
             }
-            Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => String::new(),
+            Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustcPrivate => String::new(),
         };
 
         cargo.arg("-j").arg(self.jobs().to_string());
@@ -825,7 +826,7 @@ impl Builder<'_> {
             // rustc step and one that we just built. This isn't always a
             // problem, somehow -- not really clear why -- but we know that this
             // fixes things.
-            Mode::ToolRustc => metadata.push_str("tool-rustc"),
+            Mode::ToolRustcPrivate => metadata.push_str("tool-rustc"),
             // Same for codegen backends.
             Mode::Codegen => metadata.push_str("codegen"),
             _ => {}
@@ -877,8 +878,11 @@ impl Builder<'_> {
             .env("RUSTC_LIBDIR", libdir)
             .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
             .env("RUSTDOC_REAL", rustdoc_path)
-            .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir())
-            .env("RUSTC_BREAK_ON_ICE", "1");
+            .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
+
+        if self.config.rust_break_on_ice {
+            cargo.env("RUSTC_BREAK_ON_ICE", "1");
+        }
 
         // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree
         // sysroot depending on whether we're building build scripts.
@@ -917,7 +921,7 @@ impl Builder<'_> {
         let debuginfo_level = match mode {
             Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
             Mode::Std => self.config.rust_debuginfo_level_std,
-            Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
+            Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustcPrivate | Mode::ToolTarget => {
                 self.config.rust_debuginfo_level_tools
             }
         };
@@ -930,7 +934,7 @@ impl Builder<'_> {
             match mode {
                 Mode::Std => self.config.std_debug_assertions,
                 Mode::Rustc | Mode::Codegen => self.config.rustc_debug_assertions,
-                Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
+                Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustcPrivate | Mode::ToolTarget => {
                     self.config.tools_debug_assertions
                 }
             }
@@ -1005,7 +1009,7 @@ impl Builder<'_> {
             }
             Mode::Std
             | Mode::ToolBootstrap
-            | Mode::ToolRustc
+            | Mode::ToolRustcPrivate
             | Mode::ToolStd
             | Mode::ToolTarget => {
                 if let Some(ref map_to) =
@@ -1078,7 +1082,7 @@ impl Builder<'_> {
         // requirement, but the `-L` library path is not propagated across
         // separate Cargo projects. We can add LLVM's library path to the
         // rustc args as a workaround.
-        if (mode == Mode::ToolRustc || mode == Mode::Codegen)
+        if (mode == Mode::ToolRustcPrivate || mode == Mode::Codegen)
             && let Some(llvm_config) = self.llvm_config(target)
         {
             let llvm_libdir =
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 627085df812..75c8ee36528 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -444,6 +444,7 @@ const PATH_REMAP: &[(&str, &[&str])] = &[
             "tests/mir-opt",
             "tests/pretty",
             "tests/run-make",
+            "tests/run-make-cargo",
             "tests/rustdoc",
             "tests/rustdoc-gui",
             "tests/rustdoc-js",
@@ -1061,6 +1062,7 @@ impl<'a> Builder<'a> {
                 check::FeaturesStatusDump,
                 check::CoverageDump,
                 check::Linkchecker,
+                check::BumpStage0,
                 // This has special staging logic, it may run on stage 1 while others run on stage 0.
                 // It takes quite some time to build stage 1, so put this at the end.
                 //
@@ -1127,8 +1129,8 @@ impl<'a> Builder<'a> {
                 test::RustInstaller,
                 test::TestFloatParse,
                 test::CollectLicenseMetadata,
-                // Run run-make last, since these won't pass without make on Windows
                 test::RunMake,
+                test::RunMakeCargo,
             ),
             Kind::Miri => describe!(test::Crate),
             Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index ef01f14f5e9..89a0ab7711e 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -10,8 +10,8 @@ use crate::core::build_steps::doc::DocumentationFormat;
 use crate::core::config::Config;
 use crate::utils::cache::ExecutedStep;
 use crate::utils::helpers::get_host_target;
-use crate::utils::tests::ConfigBuilder;
 use crate::utils::tests::git::{GitCtx, git_test};
+use crate::utils::tests::{ConfigBuilder, TestCtx};
 
 static TEST_TRIPLE_1: &str = "i686-unknown-haiku";
 static TEST_TRIPLE_2: &str = "i686-unknown-hurd-gnu";
@@ -22,38 +22,13 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
 }
 
 fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config {
-    let cmd = cmd.iter().copied().map(String::from).collect::<Vec<_>>();
-    let mut config = Config::parse(Flags::parse(&cmd));
-    // don't save toolstates
-    config.save_toolstates = None;
-    config.set_dry_run(DryRun::SelfCheck);
-
-    // 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(Flags::parse(&["check".to_owned()]))
-    });
-    submodule_build.require_submodule("src/doc/book", None);
-    config.submodules = Some(false);
-
-    config.ninja_in_file = false;
-    // try to avoid spurious failures in dist where we create/delete each others file
-    // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us
-    let dir = Path::new(env!("OUT_DIR"))
-        .join("tmp-rustbuild-tests")
-        .join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
-    t!(fs::create_dir_all(&dir));
-    config.out = dir;
-    config.host_target = TargetSelection::from_user(TEST_TRIPLE_1);
-    config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect();
-    config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect();
-    config
+    TestCtx::new()
+        .config(cmd[0])
+        .args(&cmd[1..])
+        .hosts(host)
+        .targets(target)
+        .args(&["--build", TEST_TRIPLE_1])
+        .create_config()
 }
 
 fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
@@ -547,8 +522,8 @@ mod snapshot {
 
     use crate::core::build_steps::{compile, dist, doc, test, tool};
     use crate::core::builder::tests::{
-        RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, configure_with_args,
-        first, host_target, render_steps, run_build,
+        RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, first, host_target,
+        render_steps, run_build,
     };
     use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata};
     use crate::core::config::TargetSelection;
@@ -1156,6 +1131,59 @@ mod snapshot {
     }
 
     #[test]
+    fn dist_compiler_docs() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("dist")
+                .path("rustc-docs")
+                .args(&["--set", "build.compiler-docs=true"])
+                .render_steps(), @r"
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
+        [doc] unstable-book (book) <host>
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [doc] book (book) <host>
+        [doc] book/first-edition (book) <host>
+        [doc] book/second-edition (book) <host>
+        [doc] book/2018-edition (book) <host>
+        [build] rustdoc 1 <host>
+        [doc] rustc 1 <host> -> standalone 2 <host>
+        [doc] rustc 1 <host> -> std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind]
+        [doc] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [doc] rustc 1 <host> -> Rustdoc 2 <host>
+        [doc] rustc 1 <host> -> Rustfmt 2 <host>
+        [build] rustc 1 <host> -> error-index 2 <host>
+        [doc] rustc 1 <host> -> error-index 2 <host>
+        [doc] nomicon (book) <host>
+        [doc] rustc 1 <host> -> reference (book) 2 <host>
+        [doc] rustdoc (book) <host>
+        [doc] rust-by-example (book) <host>
+        [build] rustc 0 <host> -> LintDocs 1 <host>
+        [doc] rustc (book) <host>
+        [doc] rustc 1 <host> -> Cargo 2 <host>
+        [doc] cargo (book) <host>
+        [doc] rustc 1 <host> -> Clippy 2 <host>
+        [doc] clippy (book) <host>
+        [doc] rustc 1 <host> -> Miri 2 <host>
+        [doc] embedded-book (book) <host>
+        [doc] edition-guide (book) <host>
+        [doc] style-guide (book) <host>
+        [build] rustdoc 0 <host>
+        [doc] rustc 0 <host> -> Tidy 1 <host>
+        [doc] rustc 0 <host> -> Bootstrap 1 <host>
+        [doc] rustc 1 <host> -> releases 2 <host>
+        [doc] rustc 0 <host> -> RunMakeSupport 1 <host>
+        [doc] rustc 0 <host> -> BuildHelper 1 <host>
+        [doc] rustc 0 <host> -> Compiletest 1 <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
+        "
+        );
+    }
+
+    #[test]
     fn dist_extended() {
         let ctx = TestCtx::new();
         insta::assert_snapshot!(
@@ -2124,8 +2152,9 @@ mod snapshot {
         [build] rustc 0 <host> -> HtmlChecker 1 <host>
         [test] html-check <host>
         [build] rustc 0 <host> -> RunMakeSupport 1 <host>
-        [build] rustc 0 <host> -> cargo 1 <host>
         [test] compiletest-run-make 1 <host>
+        [build] rustc 0 <host> -> cargo 1 <host>
+        [test] compiletest-run-make-cargo 1 <host>
         ");
     }
 
@@ -2143,7 +2172,6 @@ mod snapshot {
         [test] compiletest-ui 1 <host>
         [test] compiletest-ui-fulldeps 1 <host>
         [build] rustc 0 <host> -> RunMakeSupport 1 <host>
-        [build] rustc 0 <host> -> cargo 1 <host>
         [build] rustdoc 1 <host>
         [test] compiletest-run-make 1 <host>
         [test] compiletest-rustdoc 1 <host>
@@ -2172,7 +2200,6 @@ mod snapshot {
         [build] rustc 2 <host> -> rustc 3 <host>
         [test] compiletest-ui-fulldeps 2 <host>
         [build] rustc 0 <host> -> RunMakeSupport 1 <host>
-        [build] rustc 1 <host> -> cargo 2 <host>
         [build] rustdoc 2 <host>
         [test] compiletest-run-make 2 <host>
         [test] compiletest-rustdoc 2 <host>
@@ -2206,7 +2233,6 @@ mod snapshot {
         [build] rustc 2 <host> -> rustc 3 <target1>
         [test] compiletest-ui-fulldeps 2 <target1>
         [build] rustc 0 <host> -> RunMakeSupport 1 <host>
-        [build] rustc 1 <host> -> cargo 2 <host>
         [build] rustdoc 2 <host>
         [test] compiletest-run-make 2 <target1>
         [test] compiletest-rustdoc 2 <target1>
@@ -2301,8 +2327,9 @@ mod snapshot {
         [build] rustc 0 <host> -> HtmlChecker 1 <host>
         [test] html-check <host>
         [build] rustc 0 <host> -> RunMakeSupport 1 <host>
-        [build] rustc 1 <host> -> cargo 2 <host>
         [test] compiletest-run-make 2 <host>
+        [build] rustc 1 <host> -> cargo 2 <host>
+        [test] compiletest-run-make-cargo 2 <host>
         ");
     }
 
@@ -2436,6 +2463,43 @@ mod snapshot {
         ");
     }
 
+    // Differential snapshots for `./x test run-make` run `./x test run-make-cargo`: only
+    // `run-make-cargo` should build an in-tree cargo, running `./x test run-make` should not.
+    #[test]
+    fn test_run_make_no_cargo() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("test")
+                .path("run-make")
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 0 <host> -> RunMakeSupport 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 0 <host> -> Compiletest 1 <host>
+        [build] rustdoc 1 <host>
+        [test] compiletest-run-make 1 <host>
+        ");
+    }
+
+    #[test]
+    fn test_run_make_cargo_builds_cargo() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("test")
+                .path("run-make-cargo")
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 0 <host> -> RunMakeSupport 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 0 <host> -> Compiletest 1 <host>
+        [build] rustc 0 <host> -> cargo 1 <host>
+        [build] rustdoc 1 <host>
+        [test] compiletest-run-make-cargo 1 <host>
+        ");
+    }
+
     #[test]
     fn doc_all() {
         let ctx = TestCtx::new();
@@ -2488,6 +2552,33 @@ mod snapshot {
     }
 
     #[test]
+    fn doc_cargo_stage_1() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("doc")
+                .path("cargo")
+                .render_steps(), @r"
+        [build] rustdoc 0 <host>
+        [doc] rustc 0 <host> -> Cargo 1 <host>
+        ");
+    }
+    #[test]
+    fn doc_cargo_stage_2() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("doc")
+                .path("cargo")
+                .stage(2)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustdoc 1 <host>
+        [doc] rustc 1 <host> -> Cargo 2 <host>
+        ");
+    }
+
+    #[test]
     fn doc_core() {
         let ctx = TestCtx::new();
         insta::assert_snapshot!(
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index d12cc962187..678a9b63952 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -221,6 +221,7 @@ pub struct Config {
     pub rust_lto: RustcLto,
     pub rust_validate_mir_opts: Option<u32>,
     pub rust_std_features: BTreeSet<String>,
+    pub rust_break_on_ice: bool,
     pub llvm_profile_use: Option<String>,
     pub llvm_profile_generate: bool,
     pub llvm_libunwind_default: Option<LlvmLibunwind>,
@@ -550,6 +551,7 @@ impl Config {
             strip: rust_strip,
             lld_mode: rust_lld_mode,
             std_features: rust_std_features,
+            break_on_ice: rust_break_on_ice,
         } = toml.rust.unwrap_or_default();
 
         let Llvm {
@@ -1269,6 +1271,7 @@ impl Config {
             reproducible_artifacts: flags_reproducible_artifact,
             reuse: build_reuse.map(PathBuf::from),
             rust_analyzer_info,
+            rust_break_on_ice: rust_break_on_ice.unwrap_or(true),
             rust_codegen_backends: rust_codegen_backends
                 .map(|backends| parse_codegen_backends(backends, "rust"))
                 .unwrap_or(vec![CodegenBackendKind::Llvm]),
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
index c54df456d52..4832a1d37b7 100644
--- a/src/bootstrap/src/core/config/toml/rust.rs
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -65,6 +65,7 @@ define_config! {
         lto: Option<String> = "lto",
         validate_mir_opts: Option<u32> = "validate-mir-opts",
         std_features: Option<BTreeSet<String>> = "std-features",
+        break_on_ice: Option<bool> = "break-on-ice",
     }
 }
 
@@ -355,6 +356,7 @@ pub fn check_incompatible_options_for_ci_rustc(
         download_rustc: _,
         validate_mir_opts: _,
         frame_pointers: _,
+        break_on_ice: _,
     } = ci_rust_config;
 
     // There are two kinds of checks for CI rustc incompatible options:
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 59c0f9faaca..a2aeed20948 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -85,12 +85,12 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
 const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     (Some(Mode::Rustc), "bootstrap", None),
     (Some(Mode::Codegen), "bootstrap", None),
-    (Some(Mode::ToolRustc), "bootstrap", None),
+    (Some(Mode::ToolRustcPrivate), "bootstrap", None),
     (Some(Mode::ToolStd), "bootstrap", None),
     (Some(Mode::Rustc), "llvm_enzyme", None),
     (Some(Mode::Codegen), "llvm_enzyme", None),
-    (Some(Mode::ToolRustc), "llvm_enzyme", None),
-    (Some(Mode::ToolRustc), "rust_analyzer", None),
+    (Some(Mode::ToolRustcPrivate), "llvm_enzyme", None),
+    (Some(Mode::ToolRustcPrivate), "rust_analyzer", None),
     (Some(Mode::ToolStd), "rust_analyzer", None),
     // Any library specific cfgs like `target_os`, `target_arch` should be put in
     // priority the `[lints.rust.unexpected_cfgs.check-cfg]` table
@@ -334,17 +334,18 @@ pub enum Mode {
     /// compiletest which needs libtest.
     ToolStd,
 
-    /// Build a tool which uses the locally built rustc and the target std,
+    /// Build a tool which uses the `rustc_private` mechanism, and thus
+    /// the locally built rustc rlib artifacts,
     /// placing the output in the "stageN-tools" directory. This is used for
-    /// anything that needs a fully functional rustc, such as rustdoc, clippy,
-    /// cargo, rustfmt, miri, etc.
-    ToolRustc,
+    /// everything that links to rustc as a library, such as rustdoc, clippy,
+    /// rustfmt, miri, etc.
+    ToolRustcPrivate,
 }
 
 impl Mode {
     pub fn is_tool(&self) -> bool {
         match self {
-            Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd | Mode::ToolTarget => true,
+            Mode::ToolBootstrap | Mode::ToolRustcPrivate | Mode::ToolStd | Mode::ToolTarget => true,
             Mode::Std | Mode::Codegen | Mode::Rustc => false,
         }
     }
@@ -353,7 +354,7 @@ impl Mode {
         match self {
             Mode::Std | Mode::Codegen => true,
             Mode::ToolBootstrap
-            | Mode::ToolRustc
+            | Mode::ToolRustcPrivate
             | Mode::ToolStd
             | Mode::ToolTarget
             | Mode::Rustc => false,
@@ -924,7 +925,7 @@ impl Build {
             Mode::Rustc => (Some(build_compiler.stage + 1), "rustc"),
             Mode::Codegen => (Some(build_compiler.stage + 1), "codegen"),
             Mode::ToolBootstrap => bootstrap_tool(),
-            Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage + 1), "tools"),
+            Mode::ToolStd | Mode::ToolRustcPrivate => (Some(build_compiler.stage + 1), "tools"),
             Mode::ToolTarget => {
                 // If we're not cross-compiling (the common case), share the target directory with
                 // bootstrap tools to reuse the build cache.
@@ -1145,7 +1146,7 @@ impl Build {
                 | Mode::ToolBootstrap
                 | Mode::ToolTarget
                 | Mode::ToolStd
-                | Mode::ToolRustc,
+                | Mode::ToolRustcPrivate,
             )
             | None => target_and_stage.stage + 1,
         };
diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs
index bed03c18aaa..a6233e6b61c 100644
--- a/src/bootstrap/src/utils/cc_detect/tests.rs
+++ b/src/bootstrap/src/utils/cc_detect/tests.rs
@@ -3,7 +3,8 @@ use std::{env, iter};
 
 use super::*;
 use crate::core::config::{Target, TargetSelection};
-use crate::{Build, Config, Flags};
+use crate::utils::tests::TestCtx;
+use crate::{Build, Config, Flags, t};
 
 #[test]
 fn test_ndk_compiler_c() {
@@ -68,7 +69,8 @@ fn test_language_clang() {
 
 #[test]
 fn test_new_cc_build() {
-    let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+    let config = TestCtx::new().config("build").create_config();
+    let build = Build::new(config);
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let cfg = new_cc_build(&build, target.clone());
     let compiler = cfg.get_compiler();
@@ -77,7 +79,8 @@ fn test_new_cc_build() {
 
 #[test]
 fn test_default_compiler_wasi() {
-    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+    let config = TestCtx::new().config("build").create_config();
+    let mut build = Build::new(config);
     let target = TargetSelection::from_user("wasm32-wasi");
     let wasi_sdk = PathBuf::from("/wasi-sdk");
     build.wasi_sdk_path = Some(wasi_sdk.clone());
@@ -98,7 +101,8 @@ fn test_default_compiler_wasi() {
 
 #[test]
 fn test_default_compiler_fallback() {
-    let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+    let config = TestCtx::new().config("build").create_config();
+    let build = Build::new(config);
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let mut cfg = cc::Build::new();
     let result = default_compiler(&mut cfg, Language::C, target, &build);
@@ -107,7 +111,8 @@ fn test_default_compiler_fallback() {
 
 #[test]
 fn test_find_target_with_config() {
-    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+    let config = TestCtx::new().config("build").create_config();
+    let mut build = Build::new(config);
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let mut target_config = Target::default();
     target_config.cc = Some(PathBuf::from("dummy-cc"));
@@ -128,7 +133,8 @@ fn test_find_target_with_config() {
 
 #[test]
 fn test_find_target_without_config() {
-    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+    let config = TestCtx::new().config("build").create_config();
+    let mut build = Build::new(config);
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     build.config.target_config.clear();
     fill_target_compiler(&mut build, target.clone());
@@ -141,7 +147,8 @@ fn test_find_target_without_config() {
 
 #[test]
 fn test_find() {
-    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+    let config = TestCtx::new().config("build").create_config();
+    let mut build = Build::new(config);
     let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let target2 = TargetSelection::from_user("x86_64-unknown-openbsd");
     build.targets.push(target1.clone());
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 2cc2fb486fa..01309072927 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -536,4 +536,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "It is no longer possible to `x test` with stage 0, except for running compiletest and opting into `build.compiletest-allow-stage0`.",
     },
+    ChangeInfo {
+        change_id: 145976,
+        severity: ChangeSeverity::Info,
+        summary: "Added a new option `rust.break-on-ice` to control if internal compiler errors cause a debug break on Windows.",
+    },
 ];
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
index cf030f6830e..71de8f917fa 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
@@ -54,4 +54,4 @@ ENV RUST_CONFIGURE_ARGS \
 
 ENV SCRIPT \
   python3 ../x.py --stage 2 build && \
-  python3 ../x.py --stage 2 test tests/run-make
+  python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo
diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
index 4d5980027ca..e59012ff6af 100644
--- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
@@ -158,7 +158,7 @@ ENV RUST_CONFIGURE_ARGS \
       --disable-docs
 
 ENV SCRIPT \
-      python3 ../x.py --stage 2 test --host='' --target $RUN_MAKE_TARGETS tests/run-make && \
+      python3 ../x.py --stage 2 test --host='' --target $RUN_MAKE_TARGETS tests/run-make tests/run-make-cargo && \
       python3 ../x.py dist --host='' --target $TARGETS
 
 # sccache
diff --git a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
index 8073b8efb46..d6470e4deb8 100644
--- a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
@@ -28,6 +28,7 @@ RUN sh /scripts/sccache.sh
 
 ENV SCRIPT \
         python3 ../x.py check && \
+        python3 ../x.py check src/tools/bump-stage0 && \
         python3 ../x.py clippy ci --stage 2 && \
         python3 ../x.py test --stage 1 core alloc std test proc_macro && \
         python3 ../x.py test --stage 1 src/tools/compiletest && \
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 6ff529c9e71..e1c882d5b08 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -60,9 +60,10 @@ RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v19.0
   tar -xJ
 ENV PATH "$PATH:/wasmtime-v19.0.0-x86_64-linux"
 
-ENV WASM_WASIP_TARGET=wasm32-wasip1 
+ENV WASM_WASIP_TARGET=wasm32-wasip1
 ENV WASM_WASIP_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_WASIP_TARGET \
   tests/run-make \
+  tests/run-make-cargo \
   tests/ui \
   tests/mir-opt \
   tests/codegen-units \
@@ -73,6 +74,7 @@ ENV WASM_WASIP_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $
 ENV NVPTX_TARGETS=nvptx64-nvidia-cuda
 ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \
   tests/run-make \
+  tests/run-make-cargo \
   tests/assembly-llvm
 
 ENV MUSL_TARGETS=x86_64-unknown-linux-musl \
@@ -88,8 +90,8 @@ ENV UEFI_TARGETS=aarch64-unknown-uefi,i686-unknown-uefi,x86_64-unknown-uefi \
     CC_x86_64_unknown_uefi=clang-11 \
     CXX_x86_64_unknown_uefi=clang++-11
 ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_TARGETS && \
-  python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target aarch64-unknown-uefi && \
-  python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target i686-unknown-uefi && \
-  python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target x86_64-unknown-uefi
+  python3 /checkout/x.py --stage 2 test tests/run-make-cargo/uefi-qemu/rmake.rs --target aarch64-unknown-uefi && \
+  python3 /checkout/x.py --stage 2 test tests/run-make-cargo/uefi-qemu/rmake.rs --target i686-unknown-uefi && \
+  python3 /checkout/x.py --stage 2 test tests/run-make-cargo/uefi-qemu/rmake.rs --target x86_64-unknown-uefi
 
 ENV SCRIPT $WASM_WASIP_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
index 5052d86f0ac..7e6a59aaf89 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
@@ -56,4 +56,4 @@ ENV RUST_CONFIGURE_ARGS \
 ENV SCRIPT \
   python3 ../x.py --stage 2 build && \
   python3 ../x.py --stage 2 test tests/ui && \
-  python3 ../x.py --stage 2 test tests/run-make
+  python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo
diff --git a/src/doc/favicon.inc b/src/doc/favicon.inc
index 9c330685209..f09498cc095 100644
--- a/src/doc/favicon.inc
+++ b/src/doc/favicon.inc
@@ -1 +1,2 @@
-<link rel="icon" href="https://www.rust-lang.org/favicon.ico">
+<link rel="alternate icon" type="image/png" href="favicon-32x32.png">
+<link rel="icon" type="image/svg+xml" href="favicon.svg">
diff --git a/src/doc/redirect.inc b/src/doc/redirect.inc
index 2fb44be0145..1b7d3744b1f 100644
--- a/src/doc/redirect.inc
+++ b/src/doc/redirect.inc
@@ -1,2 +1,3 @@
 <meta name="robots" content="noindex,follow">
-<link rel="icon" href="https://www.rust-lang.org/favicon.ico">
+<link rel="alternate icon" type="image/png" href="../favicon-32x32.png">
+<link rel="icon" type="image/svg+xml" href="../favicon.svg">
diff --git a/src/doc/robots.txt b/src/doc/robots.txt
index 3a2552e9a15..71a60f89c14 100644
--- a/src/doc/robots.txt
+++ b/src/doc/robots.txt
@@ -9,3 +9,5 @@ Disallow: /beta/book/first-edition/
 Disallow: /beta/book/second-edition/
 Disallow: /nightly/book/first-edition/
 Disallow: /nightly/book/second-edition/
+
+Sitemap: https://doc.rust-lang.org/sitemap.txt
diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
index 6eabb999fb0..2dd695b7a47 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
@@ -14,7 +14,7 @@ jobs:
     if: github.repository == 'rust-lang/rustc-dev-guide'
     runs-on: ubuntu-latest
     env:
-      MDBOOK_VERSION: 0.4.48
+      MDBOOK_VERSION: 0.4.52
       MDBOOK_LINKCHECK2_VERSION: 0.9.1
       MDBOOK_MERMAID_VERSION: 0.12.6
       MDBOOK_OUTPUT__LINKCHECK__FOLLOW_WEB_LINKS: ${{ github.event_name != 'pull_request' }}
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index f412399cc8c..df2bac877b6 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-a1dbb443527bd126452875eb5d5860c1d001d761
+2f3f27bf79ec147fec9d2e7980605307a74067f4
diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md
index f3957724967..f1a406a1c29 100644
--- a/src/doc/rustc-dev-guide/src/about-this-guide.md
+++ b/src/doc/rustc-dev-guide/src/about-this-guide.md
@@ -73,7 +73,7 @@ You might also find the following sites useful:
 - [compiler-team] -- the home-base for the Rust compiler team, with description
   of the team procedures, active working groups, and the team calendar.
 - [std-dev-guide] -- a similar guide for developing the standard library.
-- [The t-compiler zulip][z]
+- [The t-compiler Zulip][z]
 - The [Rust Internals forum][rif], a place to ask questions and
   discuss Rust's internals
 - The [Rust reference][rr], even though it doesn't specifically talk about
diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md
index 65fbf752d79..4ddb58b0c39 100644
--- a/src/doc/rustc-dev-guide/src/appendix/code-index.md
+++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md
@@ -13,7 +13,7 @@ Item            |  Kind    | Short description           | Chapter            |
 `DefId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/def_id.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html)
 `Diag` | struct | A struct for a compiler diagnostic, such as an error or lint | [Emitting Diagnostics] | [compiler/rustc_errors/src/diagnostic.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html)
 `DocContext` | struct | A state container used by rustdoc when crawling through a crate to gather its documentation | [Rustdoc] | [src/librustdoc/core.rs](https://github.com/rust-lang/rust/blob/master/src/librustdoc/core.rs)
-`HirId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/hir_id.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir_id/struct.HirId.html)
+`HirId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir_id/src/lib.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.HirId.html)
 `Lexer` | struct | This is the lexer used during parsing. It consumes characters from the raw source code being compiled and produces a series of tokens for use by the rest of the parser | [The parser] |  [compiler/rustc_parse/src/lexer/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.Lexer.html)
 `NodeId` | struct | One of four types of HIR node identifiers. Being phased out | [Identifiers in the HIR] | [compiler/rustc_ast/src/ast.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/node_id/struct.NodeId.html)
 `P` | struct | An owned immutable smart pointer. By contrast, `&T` is not owned, and `Box<T>` is not immutable. | None | [compiler/rustc_ast/src/ptr.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ptr/struct.P.html)
diff --git a/src/doc/rustc-dev-guide/src/backend/debugging.md b/src/doc/rustc-dev-guide/src/backend/debugging.md
index 4f8712dfaf3..3dc95f25d4a 100644
--- a/src/doc/rustc-dev-guide/src/backend/debugging.md
+++ b/src/doc/rustc-dev-guide/src/backend/debugging.md
@@ -183,7 +183,7 @@ The quick summary is:
 ### Getting help and asking questions
 
 If you have some questions, head over to the [rust-lang Zulip] and
-specifically the `#t-compiler/wg-llvm` stream.
+specifically the `#t-compiler/wg-llvm` channel.
 
 [rust-lang Zulip]: https://rust-lang.zulipchat.com/
 
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md
index 41d0cf8d9fb..c3660e24b15 100644
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md
@@ -11,11 +11,8 @@ There are three types of tools you can write in bootstrap:
   Use this for tools that rely on the locally built std. The output goes into the "stageN-tools" directory.
   This mode is rarely used, mainly for `compiletest` which requires `libtest`.
 
-- **`Mode::ToolRustc`**
-  Use this for tools that depend on both the locally built `rustc` and the target `std`. This is more complex than
-  the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools"
-  directory. When you choose `Mode::ToolRustc`, `ToolBuild` implementation takes care of this automatically.
-  If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is
+- **`Mode::ToolRustcPrivate`**
+  Use this for tools that use the `rustc_private` mechanism, and thus depend on the locally built `rustc` and its rlib artifacts. This is more complex than the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools" directory. When you choose `Mode::ToolRustcPrivate`, `ToolBuild` implementation takes care of this automatically. If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is
   returned by the tool's [`Step`].
 
 Regardless of the tool type you must return `ToolBuildResult` from the tool’s [`Step`] implementation and use `ToolBuild` inside it.
diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md
index edd2aa6c5f6..f4514470418 100644
--- a/src/doc/rustc-dev-guide/src/compiler-debugging.md
+++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md
@@ -367,7 +367,7 @@ error: layout_of(&'a u32) = Layout {
 error: aborting due to previous error
 ```
 
-[`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/stable_mir/abi/struct.Layout.html
+[`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_public/abi/struct.Layout.html
 
 
 ## Configuring CodeLLDB for debugging `rustc`
diff --git a/src/doc/rustc-dev-guide/src/compiler-src.md b/src/doc/rustc-dev-guide/src/compiler-src.md
index d67bacb1b33..27b40f1fe01 100644
--- a/src/doc/rustc-dev-guide/src/compiler-src.md
+++ b/src/doc/rustc-dev-guide/src/compiler-src.md
@@ -153,7 +153,8 @@ The bulk of [`rustdoc`] is in [`librustdoc`]. However, the [`rustdoc`] binary
 itself is [`src/tools/rustdoc`], which does nothing except call [`rustdoc::main`].
 
 There is also `JavaScript` and `CSS` for the docs in [`src/tools/rustdoc-js`]
-and [`src/tools/rustdoc-themes`].
+and [`src/tools/rustdoc-themes`]. The type definitions for `--output-format=json`
+are in a separate crate in [`src/rustdoc-json-types`].
 
 You can read more about [`rustdoc`] in [this chapter][rustdoc-chapter].
 
@@ -162,6 +163,7 @@ You can read more about [`rustdoc`] in [this chapter][rustdoc-chapter].
 [`src/tools/rustdoc-js`]: https://github.com/rust-lang/rust/tree/master/src/tools/rustdoc-js
 [`src/tools/rustdoc-themes`]: https://github.com/rust-lang/rust/tree/master/src/tools/rustdoc-themes
 [`src/tools/rustdoc`]:  https://github.com/rust-lang/rust/tree/master/src/tools/rustdoc
+[`src/rustdoc-json-types`]: https://github.com/rust-lang/rust/tree/master/src/rustdoc-json-types
 [rustdoc-chapter]: ./rustdoc.md
 
 ## Tests
diff --git a/src/doc/rustc-dev-guide/src/compiler-team.md b/src/doc/rustc-dev-guide/src/compiler-team.md
index 9922ee7ddf2..6be52833f39 100644
--- a/src/doc/rustc-dev-guide/src/compiler-team.md
+++ b/src/doc/rustc-dev-guide/src/compiler-team.md
@@ -12,7 +12,7 @@ contributions to rustc and its design.
 Currently the compiler team chats in Zulip:
 
 - Team chat occurs in the [`t-compiler`][zulip-t-compiler] stream on the Zulip instance
-- There are also a number of other associated Zulip streams,
+- There are also a number of other associated Zulip channels,
   such as [`t-compiler/help`][zulip-help], where people can ask for help
   with rustc development, or [`t-compiler/meetings`][zulip-meetings],
   where the team holds their weekly triage and steering meetings.
diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md
index 963bef3af8d..3d196ae2308 100644
--- a/src/doc/rustc-dev-guide/src/contributing.md
+++ b/src/doc/rustc-dev-guide/src/contributing.md
@@ -26,8 +26,7 @@ conditions that trigger the bug, or part of the error message if there is any.
 An example could be: **"impossible case reached" on lifetime inference for impl
 Trait in return position**.
 
-Opening an issue is as easy as following [this
-link](https://github.com/rust-lang/rust/issues/new/choose) and filling out the fields
+Opening an issue is as easy as following [thi link][create an issue] and filling out the fields
 in the appropriate provided template.
 
 ## Bug fixes or "normal" code changes
@@ -75,7 +74,7 @@ Example of things that might require MCPs include major refactorings, changes
 to important types, or important changes to how the compiler does something, or
 smaller user-facing changes.
 
-**When in doubt, ask on [zulip]. It would be a shame to put a lot of work
+**When in doubt, ask on [Zulip]. It would be a shame to put a lot of work
 into a PR that ends up not getting merged!** [See this document][mcpinfo] for
 more info on MCPs.
 
@@ -127,7 +126,7 @@ when contributing to Rust under [the git section](./git.md).
 > from), and work with the compiler team to see if we can help you **break down a large potentially
 > unreviewable PR into a series of smaller more individually reviewable PRs**.
 >
-> You can communicate with the compiler team by creating a [#t-compiler thread on zulip][t-compiler]
+> You can communicate with the compiler team by creating a [#t-compiler thread on Zulip][t-compiler]
 > to discuss your proposed changes.
 >
 > Communicating with the compiler team beforehand helps in several ways:
@@ -154,11 +153,14 @@ The CI in rust-lang/rust applies your patches directly against the current maste
 not against the commit your branch is based on. This can lead to unexpected failures
 if your branch is outdated, even when there are no explicit merge conflicts.
 
-Before submitting or updating a PR, make sure to update your branch
-as mentioned [here](git.md#keeping-things-up-to-date) if it's significantly
-behind the master branch (e.g., more than 100 commits behind).
-This fetches the latest master branch and rebases your changes on top of it,
-ensuring your PR is tested against the latest code.
+Update your branch only when needed: when you have merge conflicts, upstream CI is broken and blocking your green PR, or a maintainer requests it.
+Avoid updating an already-green PR under review unless necessary.
+During review, make incremental commits to address feedback.
+Prefer to squash or rebase only at the end, or when a reviewer requests it.
+
+When updating, use `git push --force-with-lease` and leave a brief comment explaining what changed.
+Some repos prefer merging from `upstream/master` instead of rebasing; follow the project's conventions.
+See [keeping things up to date](git.md#keeping-things-up-to-date) for detailed instructions.
 
 After rebasing, it's recommended to [run the relevant tests locally](tests/intro.md) to catch any issues before CI runs.
 
@@ -372,6 +374,11 @@ You can also use `rustdoc` directly to check small fixes. For example,
 `rustdoc src/doc/reference.md` will render reference to `doc/reference.html`.
 The CSS might be messed up, but you can verify that the HTML is right.
 
+Please notice that we don't accept typography/spellcheck fixes to **internal documentation**
+as it's usually not worth the churn or the review time.
+Examples of internal documentation is code comments and rustc api docs.
+However, feel free to fix those if accompanied by other improvements in the same PR.
+
 ### Contributing to rustc-dev-guide
 
 Contributions to the [rustc-dev-guide] are always welcome, and can be made directly at
@@ -434,7 +441,8 @@ Just a few things to keep in mind:
 
 #### ⚠️ Note: Where to contribute `rustc-dev-guide` changes
 
-For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so, see [the rustc-dev-guide working group documentation](https://forge.rust-lang.org/wg-rustc-dev-guide/index.html#where-to-contribute-rustc-dev-guide-changes).
+For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so,
+see [the rustc-dev-guide working group documentation].
 
 ## Issue triage
 
@@ -451,6 +459,7 @@ Please see <https://forge.rust-lang.org/release/issue-triaging.html>.
 [regression-]: https://github.com/rust-lang/rust/labels?q=regression
 [relnotes]: https://github.com/rust-lang/rust/labels/relnotes
 [S-tracking-]: https://github.com/rust-lang/rust/labels?q=s-tracking
+[the rustc-dev-guide working group documentation]: https://forge.rust-lang.org/wg-rustc-dev-guide/index.html#where-to-contribute-rustc-dev-guide-changes
 
 ### Rfcbot labels
 
@@ -498,3 +507,4 @@ This section has moved to the ["About this guide"] chapter.
 [RFC 1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text
 [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
 [rdgrepo]: https://github.com/rust-lang/rustc-dev-guide
+[create an issue]: https://github.com/rust-lang/rust/issues/new/choose
diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md
index 38ba33112f2..0b341a40f1d 100644
--- a/src/doc/rustc-dev-guide/src/hir.md
+++ b/src/doc/rustc-dev-guide/src/hir.md
@@ -102,7 +102,7 @@ These identifiers can be converted into one another through the `TyCtxt`.
 
 [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
 [`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html
-[`HirId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir_id/struct.HirId.html
+[`HirId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.HirId.html
 [`BodyId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.BodyId.html
 [Node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html
 [`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/arm.md b/src/doc/rustc-dev-guide/src/notification-groups/arm.md
index 3abc32c6888..5b79030d20d 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/arm.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/arm.md
@@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing
 ARM-related issues as well as suggestions on how to resolve
 interesting questions regarding our ARM support.
 
-The group also has an associated Zulip stream ([`#t-compiler/arm`])
+The group also has an associated Zulip channel ([`#t-compiler/arm`])
 where people can go to pose questions and discuss ARM-specific
 topics.
 
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md b/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md
index 100dbdf9f2b..9e4086c884e 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md
@@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing
 Emscripten-related issues as well as suggestions on how to resolve
 interesting questions regarding our Emscripten support.
 
-The group also has an associated Zulip stream ([`#t-compiler/wasm`])
+The group also has an associated Zulip channel ([`#t-compiler/wasm`])
 where people can go to pose questions and discuss Emscripten-specific
 topics.
 
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md b/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md
index 1b31297b600..7c8a3cdf8a6 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md
@@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing
 RISC-V-related issues as well as suggestions on how to resolve
 interesting questions regarding our RISC-V support.
 
-The group also has an associated Zulip stream ([`#t-compiler/risc-v`])
+The group also has an associated Zulip channel ([`#t-compiler/risc-v`])
 where people can go to pose questions and discuss RISC-V-specific
 topics.
 
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md
index 696f2038e1a..ed1de9196de 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md
@@ -12,7 +12,7 @@ and features. The RfL maintainers should then ideally provide support
 for resolving the breakage or decide to temporarily accept the breakage
 and unblock CI by temporarily removing the RfL CI jobs.
 
-The group also has an associated Zulip stream ([`#rust-for-linux`])
+The group also has an associated Zulip channel ([`#rust-for-linux`])
 where people can go to ask questions and discuss topics related to Rust
 for Linux.
 
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/wasi.md b/src/doc/rustc-dev-guide/src/notification-groups/wasi.md
index e438ee4bd09..88b9465be01 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/wasi.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/wasi.md
@@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing
 WASI-related issues as well as suggestions on how to resolve
 interesting questions regarding our WASI support.
 
-The group also has an associated Zulip stream ([`#t-compiler/wasm`])
+The group also has an associated Zulip channel ([`#t-compiler/wasm`])
 where people can go to pose questions and discuss WASI-specific
 topics.
 
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/wasm.md b/src/doc/rustc-dev-guide/src/notification-groups/wasm.md
index c8b674cb93f..6f52b04251f 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/wasm.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/wasm.md
@@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing
 WebAssembly-related issues as well as suggestions on how to resolve
 interesting questions regarding our WASM support.
 
-The group also has an associated Zulip stream ([`#t-compiler/wasm`])
+The group also has an associated Zulip channel ([`#t-compiler/wasm`])
 where people can go to pose questions and discuss WASM-specific
 topics.
 
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/windows.md b/src/doc/rustc-dev-guide/src/notification-groups/windows.md
index e615a2cbd8d..d245208e2ab 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/windows.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/windows.md
@@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing
 Windows-related issues as well as suggestions on how to resolve
 interesting questions regarding our Windows support.
 
-The group also has an associated Zulip stream ([`#t-compiler/windows`])
+The group also has an associated Zulip channel ([`#t-compiler/windows`])
 where people can go to pose questions and discuss Windows-specific
 topics.
 
diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md
index e08f7709506..10e9452eda3 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md
@@ -1,3 +1,83 @@
 # The `rustdoc-json` test suite
 
-> **FIXME**: This section is a stub. It will be populated by [PR #2422](https://github.com/rust-lang/rustc-dev-guide/pull/2422/).
+This page is specifically about the test suite named `rustdoc-json`, which tests rustdoc's [json output].
+For other test suites used for testing rustdoc, see [§Rustdoc test suites](../tests/compiletest.md#rustdoc-test-suites).
+
+Tests are run with compiletest, and have access to the usual set of [directives](../tests/directives.md).
+Frequenly used directives here are:
+
+- [`//@ aux-build`][aux-build] to have dependencies.
+- `//@ edition: 2021` (or some other edition).
+- `//@ compile-flags: --document-hidden-items` to enable [document private items].
+
+Each crate's json output is checked by 2 programs: [jsondoclint](#jsondocck) and [jsondocck](#jsondocck).
+
+## jsondoclint
+
+[jsondoclint] checks that all [`Id`]s exist in the `index` (or `paths`).
+This makes sure there are no dangling [`Id`]s.
+
+<!-- TODO: It does some more things too?
+Also, talk about how it works
+ -->
+
+## jsondocck
+
+[jsondocck] processes direcives given in comments, to assert that the values in the output are expected.
+It's alot like [htmldocck](./rustdoc-test-suite.md) in that way.
+
+It uses [JSONPath] as a query language, which takes a path, and returns a *list* of values that that path is said to match to.
+
+### Directives
+
+- `//@ has <path>`: Checks `<path>` exists, i.e. matches at least 1 value.
+- `//@ !has <path>`: Checks `<path>` doesn't exist, i.e. matches 0 values.
+- `//@ has <path> <value>`: Check `<path>` exists, and at least 1 of the matches is equal to the given `<value>` 
+- `//@ !has <path> <value>`: Checks `<path>` exists, but none of the matches equal the given `<value>`.
+- `//@ is <path> <value>`: Check `<path>` matches exactly one value, and it's equal to the given `<value>`.
+- `//@ is <path> <value> <value>...`: Check that `<path>` matches to exactly every given `<value>`. 
+   Ordering doesn't matter here.
+- `//@ !is <path> <value>`: Check `<path>` matches exactly one value, and that value is not equal to the given `<value>`.
+- `//@ count <path> <number>`: Check that `<path>` matches to `<number>` of values.
+- `//@ set <name> = <path>`: Check that `<path>` matches exactly one value, and store that value to the variable called `<name>`.
+
+These are defined in [`directive.rs`].
+
+### Values
+
+Values can be either JSON values, or variables.
+
+- JSON values are JSON literals, e.g. `true`, `"string"`, `{"key": "value"}`. 
+  These often need to be quoted using `'`, to be processed as 1 value. See [§Argument spliting](#argument-spliting)
+- Variables can be used to store the value in one path, and use it in later queries.
+  They are set with the `//@ set <name> = <path>` directive, and accessed with `$<name>`
+
+  ```rust
+  //@ set foo = $some.path
+  //@ is $.some.other.path $foo
+  ```
+
+### Argument spliting
+
+Arguments to directives are split using the [shlex] crate, which implements POSIX shell escaping.
+This is because both `<path>` and `<value>` arguments to [directives](#directives) frequently have both
+whitespace and quote marks.
+
+To use the `@ is` with a `<path>` of `$.index[?(@.docs == "foo")].some.field` and a value of `"bar"` [^why_quote], you'd write:
+
+```rust
+//@ is '$.is[?(@.docs == "foo")].some.field' '"bar"'
+```
+
+[^why_quote]: The value needs to be `"bar"` *after* shlex splitting, because we
+    it needs to be a JSON string value.
+
+[json output]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#json-output
+[jsondocck]: https://github.com/rust-lang/rust/tree/master/src/tools/jsondocck
+[jsondoclint]: https://github.com/rust-lang/rust/tree/master/src/tools/jsondoclint
+[aux-build]: ../tests/compiletest.md#building-auxiliary-crates
+[`Id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/struct.Id.html
+[document private items]: https://doc.rust-lang.org/nightly/rustdoc/command-line-arguments.html#--document-private-items-show-items-that-are-not-public
+[`directive.rs`]: https://github.com/rust-lang/rust/blob/master/src/tools/jsondocck/src/directive.rs
+[shlex]: https://docs.rs/shlex/1.3.0/shlex/index.html
+[JSONPath]: https://www.rfc-editor.org/rfc/rfc9535.html
diff --git a/src/doc/rustc-dev-guide/src/rustdoc.md b/src/doc/rustc-dev-guide/src/rustdoc.md
index 9290fcd3b41..6127a894a0f 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc.md
@@ -107,7 +107,7 @@ This comes with several caveats: in particular, rustdoc *cannot* run any parts o
 require type-checking bodies; for example it cannot generate `.rlib` files or run most lints.
 We want to move away from this model eventually, but we need some alternative for
 [the people using it][async-std]; see [various][zulip stop accepting broken code]
-[previous][rustdoc meeting 2024-07-08] [zulip][compiler meeting 2023-01-26] [discussion][notriddle rfc].
+[previous][rustdoc meeting 2024-07-08] [Zulip][compiler meeting 2023-01-26] [discussion][notriddle rfc].
 For examples of code that breaks if this hack is removed, see
 [`tests/rustdoc-ui/error-in-impl-trait`].
 
diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md
index 8eb37bbe20b..702d3cfa6d5 100644
--- a/src/doc/rustc-dev-guide/src/serialization.md
+++ b/src/doc/rustc-dev-guide/src/serialization.md
@@ -106,7 +106,7 @@ type wrapper, like [`ty::Predicate`] and manually implementing `Encodable` and
 [`Encodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_serialize/trait.Encodable.html
 [`Encoder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_serialize/trait.Encoder.html
 [`RefDecodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/codec/trait.RefDecodable.html
-[`rustc_middle`]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_type_ir/codec.rs.html#21
+[`rustc_middle`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/index.html
 [`ty::Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/predicate/struct.Predicate.html
 [`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
 [`TyDecodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/derive.TyDecodable.html
diff --git a/src/doc/rustc-dev-guide/src/solve/caching.md b/src/doc/rustc-dev-guide/src/solve/caching.md
index e568d47ca25..cb7403de4e0 100644
--- a/src/doc/rustc-dev-guide/src/solve/caching.md
+++ b/src/doc/rustc-dev-guide/src/solve/caching.md
@@ -106,7 +106,7 @@ We can implement this optimization in the future.
 [`provisional_result`]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_trait_selection/src/solve/search_graph.rs#L57
 [initial-prov-result]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_trait_selection/src/solve/search_graph.rs#L366-L370
 [fixpoint]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_trait_selection/src/solve/search_graph.rs#L425-L446
-[^2]: summarizing the relevant [zulip thread]
+[^2]: summarizing the relevant [Zulip thread]
 
 [zulip thread]: https://rust-lang.zulipchat.com/#narrow/stream/364551-t-types.2Ftrait-system-refactor/topic/global.20cache
 [unstable-result-ex]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs#L4-L16
diff --git a/src/doc/rustc-dev-guide/src/solve/the-solver.md b/src/doc/rustc-dev-guide/src/solve/the-solver.md
index 006fb649d22..0e095b55437 100644
--- a/src/doc/rustc-dev-guide/src/solve/the-solver.md
+++ b/src/doc/rustc-dev-guide/src/solve/the-solver.md
@@ -71,6 +71,6 @@ fails.
 ## Learning more
 
 The solver should be fairly self-contained. I hope that the above information provides a
-good foundation when looking at the code itself. Please reach out on zulip if you get stuck
+good foundation when looking at the code itself. Please reach out on Zulip if you get stuck
 while doing so or there are some quirks and design decisions which were unclear and deserve
 better comments or should be mentioned here.
diff --git a/src/doc/rustc-dev-guide/src/stabilization_guide.md b/src/doc/rustc-dev-guide/src/stabilization_guide.md
index e399930fc52..7b9e1eb5629 100644
--- a/src/doc/rustc-dev-guide/src/stabilization_guide.md
+++ b/src/doc/rustc-dev-guide/src/stabilization_guide.md
@@ -82,7 +82,7 @@ Most importantly, remove the code which flags an error if the feature-gate is no
 gate_all!(pub_restricted, "`pub(restricted)` syntax is experimental");
 ```
 
-This `gate_feature_post!` macro prints an error if the `pub_restricted` feature is not enabled. It is not needed now that `#[pub_restricted]` is stable.
+The `gate_all!` macro reports an error if the `pub_restricted` feature is not enabled. It is not needed now that `pub(restricted)` is stable.
 
 For more subtle features, you may find code like this:
 
diff --git a/src/doc/rustc-dev-guide/src/tests/adding.md b/src/doc/rustc-dev-guide/src/tests/adding.md
index e5c26bef11d..46b8a1e4cf4 100644
--- a/src/doc/rustc-dev-guide/src/tests/adding.md
+++ b/src/doc/rustc-dev-guide/src/tests/adding.md
@@ -29,6 +29,8 @@ guidelines:
     suites.
   - Need to inspect the resulting binary in some way? Or if all the other test
     suites are too limited for your purposes? Then use `run-make`.
+    - Use `run-make-cargo` if you need to exercise in-tree `cargo` in conjunction
+      with in-tree `rustc`.
   - Check out the [compiletest] chapter for more specialized test suites.
 
 After deciding on which kind of test to add, see [best
diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md
index be00207e3fb..efc626035b7 100644
--- a/src/doc/rustc-dev-guide/src/tests/best-practices.md
+++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md
@@ -83,10 +83,10 @@ related tests.
     - E.g. for an implementation of RFC 2093 specifically, we can group a
       collection of tests under `tests/ui/rfc-2093-infer-outlives/`. For the
       directory name, include what the RFC is about.
-- For the [`run-make`] test suite, each `rmake.rs` must be contained within an
-  immediate subdirectory under `tests/run-make/`. Further nesting is not
-  presently supported. Avoid including issue number in the directory name too,
-  include that info in a comment inside `rmake.rs`.
+- For the [`run-make`]/`run-make-support` test suites, each `rmake.rs` must
+  be contained within an immediate subdirectory under `tests/run-make/` or
+  `tests/run-make-cargo/` respectively. Further nesting is not presently
+  supported. Avoid using _only_ an issue number for the test name as well.
 
 ## Test descriptions
 
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index 4980ed845d6..a4a729935fa 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -397,13 +397,19 @@ your test, causing separate files to be generated for 32bit and 64bit systems.
 
 ### `run-make` tests
 
-The tests in [`tests/run-make`] are general-purpose tests using Rust *recipes*,
-which are small programs (`rmake.rs`) allowing arbitrary Rust code such as
-`rustc` invocations, and is supported by a [`run_make_support`] library. Using
-Rust recipes provide the ultimate in flexibility.
+The tests in [`tests/run-make`] and [`tests/run-make-cargo`] are general-purpose
+tests using Rust *recipes*, which are small programs (`rmake.rs`) allowing
+arbitrary Rust code such as `rustc` invocations, and is supported by a
+[`run_make_support`] library. Using Rust recipes provide the ultimate in
+flexibility.
 
 `run-make` tests should be used if no other test suites better suit your needs.
 
+The `run-make-cargo` test suite additionally builds an in-tree `cargo` to support
+use cases that require testing in-tree `cargo` in conjunction with in-tree `rustc`.
+The `run-make` test suite does not have access to in-tree `cargo` (so it can be the
+faster-to-iterate test suite).
+
 #### Using Rust recipes
 
 Each test should be in a separate directory with a `rmake.rs` Rust program,
@@ -476,6 +482,7 @@ Then add a corresponding entry to `"rust-analyzer.linkedProjects"`
 ```
 
 [`tests/run-make`]: https://github.com/rust-lang/rust/tree/master/tests/run-make
+[`tests/run-make-cargo`]: https://github.com/rust-lang/rust/tree/master/tests/run-make-cargo
 [`run_make_support`]: https://github.com/rust-lang/rust/tree/master/src/tools/run-make-support
 
 ### Coverage tests
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index fbbeb7e97d3..4be78fac4ec 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -36,9 +36,9 @@ directive.
 The following is a list of compiletest directives. Directives are linked to
 sections that describe the command in more detail if available. This list may
 not be exhaustive. Directives can generally be found by browsing the
-`TestProps` structure found in [`header.rs`] from the compiletest source.
+`TestProps` structure found in [`directives.rs`] from the compiletest source.
 
-[`header.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/header.rs
+[`directives.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/directives.rs
 
 ### Assembly
 
@@ -52,14 +52,14 @@ not be exhaustive. Directives can generally be found by browsing the
 
 See [Building auxiliary crates](compiletest.html#building-auxiliary-crates)
 
-| Directive             | Explanation                                                                                           | Supported test suites | Possible values                               |
-|-----------------------|-------------------------------------------------------------------------------------------------------|-----------------------|-----------------------------------------------|
-| `aux-bin`             | Build a aux binary, made available in `auxiliary/bin` relative to test directory                      | All except `run-make` | Path to auxiliary `.rs` file                  |
-| `aux-build`           | Build a separate crate from the named source file                                                     | All except `run-make` | Path to auxiliary `.rs` file                  |
-| `aux-crate`           | Like `aux-build` but makes available as extern prelude                                                | All except `run-make` | `<extern_prelude_name>=<path/to/aux/file.rs>` |
-| `aux-codegen-backend` | Similar to `aux-build` but pass the compiled dylib to `-Zcodegen-backend` when building the main file | `ui-fulldeps`         | Path to codegen backend file                  |
-| `proc-macro`          | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm].                | All except `run-make` | Path to auxiliary proc-macro `.rs` file       |
-| `build-aux-docs`      | Build docs for auxiliaries as well.  Note that this only works with `aux-build`, not `aux-crate`.     | All except `run-make` | N/A                                           |
+| Directive             | Explanation                                                                                           | Supported test suites                  | Possible values                               |
+|-----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------|-----------------------------------------------|
+| `aux-bin`             | Build a aux binary, made available in `auxiliary/bin` relative to test directory                      | All except `run-make`/`run-make-cargo` | Path to auxiliary `.rs` file                  |
+| `aux-build`           | Build a separate crate from the named source file                                                     | All except `run-make`/`run-make-cargo` | Path to auxiliary `.rs` file                  |
+| `aux-crate`           | Like `aux-build` but makes available as extern prelude                                                | All except `run-make`/`run-make-cargo` | `<extern_prelude_name>=<path/to/aux/file.rs>` |
+| `aux-codegen-backend` | Similar to `aux-build` but pass the compiled dylib to `-Zcodegen-backend` when building the main file | `ui-fulldeps`                          | Path to codegen backend file                  |
+| `proc-macro`          | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm].                | All except `run-make`/`run-make-cargo` | Path to auxiliary proc-macro `.rs` file       |
+| `build-aux-docs`      | Build docs for auxiliaries as well.  Note that this only works with `aux-build`, not `aux-crate`.     | All except `run-make`/`run-make-cargo` | N/A                                           |
 
 [^pm]: please see the [Auxiliary proc-macro section](compiletest.html#auxiliary-proc-macro) in the compiletest chapter for specifics.
 
@@ -243,18 +243,18 @@ ignoring debuggers.
 
 ### Affecting how tests are built
 
-| Directive           | Explanation                                                                                  | Supported test suites     | Possible values                                                                            |
-|---------------------|----------------------------------------------------------------------------------------------|---------------------------|--------------------------------------------------------------------------------------------|
-| `compile-flags`     | Flags passed to `rustc` when building the test or aux file                                   | All except for `run-make` | Any valid `rustc` flags, e.g. `-Awarnings -Dfoo`. Cannot be `-Cincremental` or `--edition` |
-| `edition`           | The edition used to build the test                                                           | All except for `run-make` | Any valid `--edition` value                                                                |
-| `rustc-env`         | Env var to set when running `rustc`                                                          | All except for `run-make` | `<KEY>=<VALUE>`                                                                            |
-| `unset-rustc-env`   | Env var to unset when running `rustc`                                                        | All except for `run-make` | Any env var name                                                                           |
-| `incremental`       | Proper incremental support for tests outside of incremental test suite                       | `ui`, `crashes`           | N/A                                                                                        |
-| `no-prefer-dynamic` | Don't use `-C prefer-dynamic`, don't build as a dylib via a `--crate-type=dylib` preset flag | `ui`, `crashes`           | N/A                                                                                        |
+| Directive           | Explanation                                                                                  | Supported test suites                      | Possible values                                                                            |
+|---------------------|----------------------------------------------------------------------------------------------|--------------------------------------------|--------------------------------------------------------------------------------------------|
+| `compile-flags`     | Flags passed to `rustc` when building the test or aux file                                   | All except for `run-make`/`run-make-cargo` | Any valid `rustc` flags, e.g. `-Awarnings -Dfoo`. Cannot be `-Cincremental` or `--edition` |
+| `edition`           | The edition used to build the test                                                           | All except for `run-make`/`run-make-cargo` | Any valid `--edition` value                                                                |
+| `rustc-env`         | Env var to set when running `rustc`                                                          | All except for `run-make`/`run-make-cargo` | `<KEY>=<VALUE>`                                                                            |
+| `unset-rustc-env`   | Env var to unset when running `rustc`                                                        | All except for `run-make`/`run-make-cargo` | Any env var name                                                                           |
+| `incremental`       | Proper incremental support for tests outside of incremental test suite                       | `ui`, `crashes`                            | N/A                                                                                        |
+| `no-prefer-dynamic` | Don't use `-C prefer-dynamic`, don't build as a dylib via a `--crate-type=dylib` preset flag | `ui`, `crashes`                            | N/A                                                                                        |
 
 <div class="warning">
 
-Tests (outside of `run-make`) that want to use incremental tests not in the
+Tests (outside of `run-make`/`run-make-cargo`) that want to use incremental tests not in the
 incremental test-suite must not pass `-C incremental` via `compile-flags`, and
 must instead use the `//@ incremental` directive.
 
@@ -264,9 +264,9 @@ Consider writing the test as a proper incremental test instead.
 
 ### Rustdoc
 
-| Directive   | Explanation                                                  | Supported test suites                    | Possible values           |
-|-------------|--------------------------------------------------------------|------------------------------------------|---------------------------|
-| `doc-flags` | Flags passed to `rustdoc` when building the test or aux file | `rustdoc`, `rustdoc-js`, `rustdoc-json`  | Any valid `rustdoc` flags |
+| Directive   | Explanation                                                  | Supported test suites                   | Possible values           |
+|-------------|--------------------------------------------------------------|-----------------------------------------|---------------------------|
+| `doc-flags` | Flags passed to `rustdoc` when building the test or aux file | `rustdoc`, `rustdoc-js`, `rustdoc-json` | Any valid `rustdoc` flags |
 
 <!--
 **FIXME(rustdoc)**: what does `check-test-line-numbers-match` do?
@@ -374,7 +374,7 @@ the directive's backing store (holds the command's current value) at runtime.
 To add a new directive property:
 
 1. Look for the `pub struct TestProps` declaration in
-   [`src/tools/compiletest/src/header.rs`] and add the new public property to
+   [`src/tools/compiletest/src/directives.rs`] and add the new public property to
    the end of the declaration.
 2. Look for the `impl TestProps` implementation block immediately following the
    struct declaration and initialize the new property to its default value.
@@ -383,7 +383,7 @@ To add a new directive property:
 
 When `compiletest` encounters a test file, it parses the file a line at a time
 by calling every parser defined in the `Config` struct's implementation block,
-also in [`src/tools/compiletest/src/header.rs`] (note that the `Config` struct's
+also in [`src/tools/compiletest/src/directives.rs`] (note that the `Config` struct's
 declaration block is found in [`src/tools/compiletest/src/common.rs`]).
 `TestProps`'s `load_from()` method will try passing the current line of text to
 each parser, which, in turn typically checks to see if the line begins with a
@@ -406,7 +406,7 @@ and their associated parsers immediately above to see how they are used to avoid
 writing additional parsing code unnecessarily.
 
 As a concrete example, here is the implementation for the
-`parse_failure_status()` parser, in [`src/tools/compiletest/src/header.rs`]:
+`parse_failure_status()` parser, in [`src/tools/compiletest/src/directives.rs`]:
 
 ```diff
 @@ -232,6 +232,7 @@ pub struct TestProps {
@@ -508,6 +508,6 @@ example, `//@ failure-status: 1`, `self.props.failure_status` will evaluate to
 1, as `parse_failure_status()` will have overridden the `TestProps` default
 value, for that test specifically.
 
-[`src/tools/compiletest/src/header.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/header.rs
+[`src/tools/compiletest/src/directives.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/directives.rs
 [`src/tools/compiletest/src/common.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/common.rs
 [`src/tools/compiletest/src/runtest.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/runtest.rs
diff --git a/src/doc/rustc-dev-guide/src/tests/misc.md b/src/doc/rustc-dev-guide/src/tests/misc.md
index 39f88174879..cc8f501224f 100644
--- a/src/doc/rustc-dev-guide/src/tests/misc.md
+++ b/src/doc/rustc-dev-guide/src/tests/misc.md
@@ -24,8 +24,8 @@ In `ui` tests and other test suites that support `//@ rustc-env`, you can specif
 //@ rustc-env:RUSTC_BOOTSTRAP=-1
 ```
 
-For `run-make` tests, `//@ rustc-env` is not supported. You can do something
-like the following for individual `rustc` invocations.
+For `run-make`/`run-make-cargo` tests, `//@ rustc-env` is not supported. You can do
+something like the following for individual `rustc` invocations.
 
 ```rust,ignore
 use run_make_support::rustc;
diff --git a/src/doc/rustc-dev-guide/src/traits/chalk.md b/src/doc/rustc-dev-guide/src/traits/chalk.md
index 844f42b9879..ca5ed525917 100644
--- a/src/doc/rustc-dev-guide/src/traits/chalk.md
+++ b/src/doc/rustc-dev-guide/src/traits/chalk.md
@@ -5,7 +5,7 @@
 Its goal is to enable a lot of trait system features and bug fixes
 that are hard to implement (e.g. GATs or specialization). If you would like to
 help in hacking on the new solver, drop by on the rust-lang Zulip in the [`#t-types`]
-stream and say hello!
+channel and say hello!
 
 [Types team]: https://github.com/rust-lang/types-team
 [`#t-types`]: https://rust-lang.zulipchat.com/#narrow/stream/144729-t-types
diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md
index 2243205f129..24982a209fd 100644
--- a/src/doc/rustc-dev-guide/src/type-inference.md
+++ b/src/doc/rustc-dev-guide/src/type-inference.md
@@ -239,13 +239,13 @@ differently. It uses canonical queries for trait solving which use
 [`take_and_reset_region_constraints`] at the end. This extracts all of the
 outlives constraints added during the canonical query. This is required
 as the NLL solver must not only know *what* regions outlive each other,
-but also *where*. Finally, the NLL solver invokes [`take_region_var_origins`],
+but also *where*. Finally, the NLL solver invokes [`get_region_var_infos`],
 providing all region variables to the solver.
 
-[`resolve_regions_and_report_errors`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.resolve_regions_and_report_errors
+[`resolve_regions_and_report_errors`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html#method.resolve_regions_and_report_errors
 [`lexical_region_resolve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/lexical_region_resolve/index.html
 [`take_and_reset_region_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.take_and_reset_region_constraints
-[`take_region_var_origins`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.take_region_var_origins
+[`get_region_var_infos`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.get_region_var_infos
 
 ## Lexical region resolution
 
diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
index db15467a47a..45635ebfa15 100644
--- a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
+++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
@@ -2,11 +2,14 @@
 
 ## Typing Environments
 
-When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively).
+When interacting with the type system there are a few variables to consider that can affect the results of trait solving.
+The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively).
 
-When an environment to perform type system operations in has not yet been created, the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type.
+When an environment to perform type system operations in has not yet been created,
+the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type.
 
-Once a context to perform type system operations in has been created (e.g. an [`ObligationCtxt`][ocx] or [`FnCtxt`][fnctxt]) a `TypingEnv` is typically not stored anywhere as only the `TypingMode` is a property of the whole environment, whereas different `ParamEnv`s can be used on a per-goal basis.
+Once a context to perform type system operations in has been created (e.g. an [`ObligationCtxt`][ocx] or [`FnCtxt`][fnctxt]) a `TypingEnv` is typically not stored anywhere as only the `TypingMode` is a property of the whole environment,
+whereas different `ParamEnv`s can be used on a per-goal basis.
 
 [ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html
 [fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html
@@ -15,9 +18,14 @@ Once a context to perform type system operations in has been created (e.g. an [`
 
 ### What is a `ParamEnv`
 
-The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds.
+The [`ParamEnv`][penv] is a list of in-scope where-clauses,
+it typically corresponds to a specific item's where clauses.
+Some clauses are not explicitly written but are instead implicitly added in the [`predicates_of`][predicates_of] query,
+such as `ConstArgHasType` or (some) implied bounds.
 
-In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses.
+In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses.
+A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item,
+such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses.
 
 ---
 
@@ -30,7 +38,9 @@ where
     <T as Trait>::Assoc: Clone,
 {}
 ```
-If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system. This would allow things such as [normalization], evaluating generic constants, and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc.
+If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system.
+This would allow things such as [normalization], evaluating generic constants,
+and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc.
 
 A more concrete example:
 ```rust
@@ -72,9 +82,13 @@ fn foo2<T>(a: T) {
 
 ### Acquiring a `ParamEnv`
 
-Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroring when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs.
+Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs,
+illformed programs compiling, or erroring when we shouldn't.
+See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs.
 
-In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`:
+In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope,
+or above in the call stack and should be passed down.
+A non exhaustive list of places where you might find an existing `ParamEnv`:
 - During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env]
 - When writing late lints the `LateContext` has a [`param_env` field][latectxt_param_env]
 - During well formedness checking the `WfCheckingCtxt` has a [`param_env` field][wfckctxt_param_env]
@@ -82,16 +96,20 @@ In the large majority of cases, when a `ParamEnv` is required it either already
 - In the next-gen trait solver all `Goal`s have a [`param_env` field][goal_param_env] specifying what environment to prove the goal in
 - When editing an existing [`TypeRelation`][typerelation] if it implements [`PredicateEmittingRelation`][predicate_emitting_relation] then a [`param_env` method][typerelation_param_env] will be available.
 
-If you aren't sure if there's a `ParamEnv` in scope somewhere that can be used it can be worth opening a thread in the [`#t-compiler/help`][compiler_help] zulip stream where someone may be able to point out where a `ParamEnv` can be acquired from.
+If you aren't sure if there's a `ParamEnv` in scope somewhere that can be used it can be worth opening a thread in the [`#t-compiler/help`][compiler_help] Zulip channel where someone may be able to point out where a `ParamEnv` can be acquired from.
 
-Manually constructing a `ParamEnv` is typically only needed at the start of some kind of top level analysis (e.g. hir typeck or borrow checking). In such cases there are three ways it can be done:
+Manually constructing a `ParamEnv` is typically only needed at the start of some kind of top level analysis (e.g. hir typeck or borrow checking).
+In such cases there are three ways it can be done:
 - Calling the [`tcx.param_env(def_id)` query][param_env_query] which returns the environment associated with a given definition.
 - Creating an empty environment with [`ParamEnv::empty`][env_empty].
-- Using [`ParamEnv::new`][param_env_new] to construct an env with an arbitrary set of where clauses. Then calling [`traits::normalize_param_env_or_error`][normalize_env_or_error] to handle normalizing and elaborating all the where clauses in the env.
+- Using [`ParamEnv::new`][param_env_new] to construct an env with an arbitrary set of where clauses.
+  Then calling [`traits::normalize_param_env_or_error`][normalize_env_or_error] to handle normalizing and elaborating all the where clauses in the env.
 
 Using the `param_env` query is by far the most common way to construct a `ParamEnv` as most of the time the compiler is performing an analysis as part of some specific definition.
 
-Creating an empty environment with `ParamEnv::empty` is typically only done either in codegen (indirectly via [`TypingEnv::fully_monomorphized`][tenv_mono]), or as part of some analysis that do not expect to ever encounter generic parameters (e.g. various parts of coherence/orphan check).
+Creating an empty environment with `ParamEnv::empty` is typically only done either in codegen (indirectly via [`TypingEnv::fully_monomorphized`][tenv_mono]),
+or as part of some analysis that do not expect to ever encounter generic parameters
+(e.g. various parts of coherence/orphan check).
 
 Creating an env from an arbitrary set of where clauses is usually unnecessary and should only be done if the environment you need does not correspond to an actual item in the source code (e.g. [`compare_method_predicate_entailment`][method_pred_entailment]).
 
@@ -113,11 +131,14 @@ Creating an env from an arbitrary set of where clauses is usually unnecessary an
 
 ### How are `ParamEnv`s constructed
 
-Creating a [`ParamEnv`][pe] is more complicated than simply using the list of where clauses defined on an item as written by the user. We need to both elaborate supertraits into the env and fully normalize all aliases. This logic is handled by [`traits::normalize_param_env_or_error`][normalize_env_or_error] (even though it does not mention anything about elaboration).
+Creating a [`ParamEnv`][pe] is more complicated than simply using the list of where clauses defined on an item as written by the user.
+We need to both elaborate supertraits into the env and fully normalize all aliases.
+This logic is handled by [`traits::normalize_param_env_or_error`][normalize_env_or_error] (even though it does not mention anything about elaboration).
 
 #### Elaborating supertraits
 
-When we have a function such as `fn foo<T: Copy>()` we would like to be able to prove `T: Clone` inside of the function as the `Copy` trait has a `Clone` supertrait. Constructing a `ParamEnv` looks at all of the trait bounds in the env and explicitly adds new where clauses to the `ParamEnv` for any supertraits found on the traits.
+When we have a function such as `fn foo<T: Copy>()` we would like to be able to prove `T: Clone` inside of the function as the `Copy` trait has a `Clone` supertrait.
+Constructing a `ParamEnv` looks at all of the trait bounds in the env and explicitly adds new where clauses to the `ParamEnv` for any supertraits found on the traits.
 
 A concrete example would be the following function:
 ```rust
@@ -133,13 +154,16 @@ fn bar<T: Copy + Trait>(a: T) {
 fn requires_impl<T: Clone + SuperSuperTrait>(a: T) {}
 ```
 
-If we did not elaborate the env then the `requires_impl` call would fail to typecheck as we would not be able to prove `T: Clone` or `T: SuperSuperTrait`. In practice we elaborate the env which means that `bar`'s `ParamEnv` is actually:
+If we did not elaborate the env then the `requires_impl` call would fail to typecheck as we would not be able to prove `T: Clone` or `T: SuperSuperTrait`.
+In practice we elaborate the env which means that `bar`'s `ParamEnv` is actually:
 `[T: Sized, T: Copy, T: Clone, T: Trait, T: SuperTrait, T: SuperSuperTrait]`
 This allows us to prove `T: Clone` and `T: SuperSuperTrait` when type checking `bar`.
 
 The `Clone` trait has a `Sized` supertrait however we do not end up with two `T: Sized` bounds in the env (one for the supertrait and one for the implicitly added `T: Sized` bound) as the elaboration process (implemented via [`util::elaborate`][elaborate]) deduplicates where clauses.
 
-A side effect of this is that even if no actual elaboration of supertraits takes place, the existing where clauses in the env are _also_ deduplicated. See the following example:
+A side effect of this is that even if no actual elaboration of supertraits takes place,
+the existing where clauses in the env are _also_ deduplicated.
+See the following example:
 ```rust
 trait Trait {}
 // The unelaborated `ParamEnv` would be:
@@ -156,7 +180,8 @@ The [next-gen trait solver][next-gen-solver] also requires this elaboration to t
 
 #### Normalizing all bounds
 
-In the old trait solver the where clauses stored in `ParamEnv` are required to be fully normalized as otherwise the trait solver will not function correctly. A concrete example of needing to normalize the `ParamEnv` is the following:
+In the old trait solver the where clauses stored in `ParamEnv` are required to be fully normalized as otherwise the trait solver will not function correctly.
+A concrete example of needing to normalize the `ParamEnv` is the following:
 ```rust
 trait Trait<T> {
     type Assoc;
@@ -182,11 +207,14 @@ where
 fn requires_impl<U: Trait<u32>>(_: U) {}
 ```
 
-As humans we can tell that `<T as Other>::Bar` is equal to `u32` so the trait bound on `U` is equivalent to `U: Trait<u32>`. In practice trying to prove `U: Trait<u32>` in the old solver in this environment would fail as it is unable to determine that `<T as Other>::Bar` is equal to `u32`.
+As humans we can tell that `<T as Other>::Bar` is equal to `u32` so the trait bound on `U` is equivalent to `U: Trait<u32>`.
+In practice trying to prove `U: Trait<u32>` in the old solver in this environment would fail as it is unable to determine that `<T as Other>::Bar` is equal to `u32`.
 
 To work around this we normalize `ParamEnv`'s after constructing them so that `foo`'s `ParamEnv` is actually: `[T: Sized, U: Sized, U: Trait<u32>]` which means the trait solver is now able to use the `U: Trait<u32>` in the `ParamEnv` to determine that the trait bound `U: Trait<u32>` holds.
 
-This workaround does not work in all cases as normalizing associated types requires a `ParamEnv` which introduces a bootstrapping problem. We need a normalized `ParamEnv` in order for normalization to give correct results, but we need to normalize to get that `ParamEnv`. Currently we normalize the `ParamEnv` once using the unnormalized param env and it tends to give okay results in practice even though there are some examples where this breaks ([example]).
+This workaround does not work in all cases as normalizing associated types requires a `ParamEnv` which introduces a bootstrapping problem.
+We need a normalized `ParamEnv` in order for normalization to give correct results, but we need to normalize to get that `ParamEnv`.
+Currently we normalize the `ParamEnv` once using the unnormalized param env and it tends to give okay results in practice even though there are some examples where this breaks ([example]).
 
 In the next-gen trait solver the requirement for all where clauses in the `ParamEnv` to be fully normalized is not present and so we do not normalize when constructing `ParamEnv`s.
 
@@ -196,9 +224,12 @@ In the next-gen trait solver the requirement for all where clauses in the `Param
 
 ## Typing Modes
 
-Depending on what context we are performing type system operations in, different behaviour may be required. For example during coherence there are stronger requirements about when we can consider goals to not hold or when we can consider types to be unequal.
+Depending on what context we are performing type system operations in,
+different behaviour may be required.
+For example during coherence there are stronger requirements about when we can consider goals to not hold or when we can consider types to be unequal.
 
-Tracking which "phase" of the compiler type system operations are being performed in is done by the [`TypingMode`][tmode] enum. The documentation on the `TypingMode` enum is quite good so instead of repeating it here verbatim we would recommend reading the API documentation directly.
+Tracking which "phase" of the compiler type system operations are being performed in is done by the [`TypingMode`][tmode] enum.
+The documentation on the `TypingMode` enum is quite good so instead of repeating it here verbatim we would recommend reading the API documentation directly.
 
 [penv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
 [tenv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypingEnv.html
diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml
index 3ac5d57a52b..4a885239152 100644
--- a/src/doc/rustc-dev-guide/triagebot.toml
+++ b/src/doc/rustc-dev-guide/triagebot.toml
@@ -90,7 +90,6 @@ does not need reviews. You can request a review using `r? rustc-dev-guide` or \
 [assign.adhoc_groups]
 rustc-dev-guide = [
     "@BoxyUwU",
-    "@jieyouxu",
     "@jyn514",
     "@tshepang",
 ]
diff --git a/src/doc/rustc/src/command-line-arguments/print-options.md b/src/doc/rustc/src/command-line-arguments/print-options.md
index fed19d6b667..f37b27d88c3 100644
--- a/src/doc/rustc/src/command-line-arguments/print-options.md
+++ b/src/doc/rustc/src/command-line-arguments/print-options.md
@@ -184,7 +184,7 @@ Example:
 
 ```bash
 $ rustc --print native-static-libs --crate-type staticlib a.rs
-note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
+note: link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
 
 note: native-static-libs: -lgcc_s -lutil [REDACTED] -lpthread -lm -ldl -lc
 ```
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index dfe193e6e8a..6c5b48d8c8f 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-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
+[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+)
 [`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
@@ -88,7 +89,6 @@ so Rustup may install the documentation for a similar tier 1 target instead.
 target | notes
 -------|-------
 [`aarch64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ARM64 MinGW (Windows 10+), LLVM ABI
-[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC
 [`aarch64-unknown-linux-musl`](platform-support/aarch64-unknown-linux-musl.md) | ARM64 Linux with musl 1.2.3
 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony
 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17)
diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md
index 71dc4ddc2e6..826c75b79c5 100644
--- a/src/doc/rustc/src/platform-support/windows-msvc.md
+++ b/src/doc/rustc/src/platform-support/windows-msvc.md
@@ -4,13 +4,10 @@ Windows MSVC targets.
 
 **Tier 1 with host tools:**
 
+- `aarch64-pc-windows-msvc`: Windows on ARM64.
 - `i686-pc-windows-msvc`: Windows on 32-bit x86.
 - `x86_64-pc-windows-msvc`: Windows on 64-bit x86.
 
-**Tier 2 with host tools:**
-
-- `aarch64-pc-windows-msvc`: Windows on ARM64.
-
 ## Target maintainers
 
 [@ChrisDenton](https://github.com/ChrisDenton)
diff --git a/src/doc/sitemap.txt b/src/doc/sitemap.txt
new file mode 100644
index 00000000000..6e5f0fbad37
--- /dev/null
+++ b/src/doc/sitemap.txt
@@ -0,0 +1,4 @@
+https://doc.rust-lang.org/stable/
+https://doc.rust-lang.org/beta/
+https://doc.rust-lang.org/nightly/
+
diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md
index f42b9cb5978..c3788c97ae6 100644
--- a/src/doc/style-guide/src/README.md
+++ b/src/doc/style-guide/src/README.md
@@ -112,6 +112,14 @@ fn bar() {}
 fn baz() {}
 ```
 
+### Trailing whitespace
+
+Do not include trailing whitespace on the end of any line. This includes blank
+lines, comment lines, code lines, and string literals.
+
+Note that avoiding trailing whitespace in string literals requires care to
+preserve the value of the literal.
+
 ### Sorting
 
 In various cases, the default Rust style specifies to sort things. If not
@@ -225,8 +233,8 @@ newline after the opening sigil, and a newline before the closing sigil.
 
 Prefer to put a comment on its own line. Where a comment follows code, put a
 single space before it. Where a block comment appears inline, use surrounding
-whitespace as if it were an identifier or keyword. Do not include trailing
-whitespace after a comment or at the end of any line in a multi-line comment.
+whitespace as if it were an identifier or keyword.
+
 Examples:
 
 ```rust
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 2f9d4d22e5a..493256de99d 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -244,18 +244,16 @@ See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
 
 ## Example 1: Redirecting control flow using an indirect branch/call to an invalid destination
 
-```rust,ignore (making doc tests pass cross-platform is hard)
-use std::arch::naked_asm;
-use std::mem;
-
+```rust
 fn add_one(x: i32) -> i32 {
     x + 1
 }
 
 #[unsafe(naked)]
-pub extern "C" fn add_two(x: i32) {
+# #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+pub extern "sysv64" fn add_two(x: i32) {
     // x + 2 preceded by a landing pad/nop block
-    naked_asm!(
+    std::arch::naked_asm!(
         "
          nop
          nop
@@ -281,16 +279,18 @@ fn main() {
 
     println!("The answer is: {}", answer);
 
-    println!("With CFI enabled, you should not see the next answer");
-    let f: fn(i32) -> i32 = unsafe {
-        // Offset 0 is a valid branch/call destination (i.e., the function entry
-        // point), but offsets 1-8 within the landing pad/nop block are invalid
-        // branch/call destinations (i.e., within the body of the function).
-        mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
-    };
-    let next_answer = do_twice(f, 5);
-
-    println!("The next answer is: {}", next_answer);
+#   #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
+        println!("With CFI enabled, you should not see the next answer");
+        let f: fn(i32) -> i32 = unsafe {
+            // Offset 0 is a valid branch/call destination (i.e., the function entry
+            // point), but offsets 1-8 within the landing pad/nop block are invalid
+            // branch/call destinations (i.e., within the body of the function).
+            std::mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
+        };
+        let next_answer = do_twice(f, 5);
+
+        println!("The next answer is: {}", next_answer);
+#   }
 }
 ```
 Fig. 1. Redirecting control flow using an indirect branch/call to an invalid
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 8d7f7341c2e..46a3a1602ac 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -247,7 +247,7 @@ class CachedFiles(object):
             paths = list(Path(self.root).glob(path))
             if len(paths) != 1:
                 raise FailedCheck("glob path does not resolve to one file")
-            path = str(paths[0])
+            return str(paths[0])
         return os.path.join(self.root, path)
 
     def get_file(self, path):
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 5d36ffc2d3a..f37a8d85361 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -21,7 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.8.1"
-stringdex = { version = "0.0.1-alpha4" }
+stringdex = { version = "0.0.1-alpha9" }
 tempfile = "3"
 threadpool = "1.8.1"
 tracing = "0.1"
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 450ac04b40d..d7f6fa347be 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -454,15 +454,22 @@ impl Options {
             return None;
         }
 
-        let mut emit = Vec::new();
+        let mut emit = FxIndexMap::<_, EmitType>::default();
         for list in matches.opt_strs("emit") {
             for kind in list.split(',') {
                 match kind.parse() {
-                    Ok(kind) => emit.push(kind),
+                    Ok(kind) => {
+                        // De-duplicate emit types and the last wins.
+                        // Only one instance for each type is allowed
+                        // regardless the actual data it carries.
+                        // This matches rustc's `--emit` behavior.
+                        emit.insert(std::mem::discriminant(&kind), kind);
+                    }
                     Err(()) => dcx.fatal(format!("unrecognized emission type: {kind}")),
                 }
             }
         }
+        let emit = emit.into_values().collect::<Vec<_>>();
 
         let show_coverage = matches.opt_present("show-coverage");
         let output_format_s = matches.opt_str("output-format");
@@ -814,7 +821,8 @@ impl Options {
 
         let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
         let with_examples = matches.opt_strs("with-examples");
-        let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);
+        let call_locations =
+            crate::scrape_examples::load_call_locations(with_examples, dcx, &mut loaded_paths);
         let doctest_build_args = matches.opt_strs("doctest-build-arg");
 
         let unstable_features =
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 5da37c97c6a..b01b596da68 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1212,7 +1212,7 @@ class DocSearch {
      * will never fulfill.
      */
     async buildIndex() {
-        const nn = this.database.getIndex("normalizedName");
+        const nn = this.database.getData("normalizedName");
         if (!nn) {
             return;
         }
@@ -3722,7 +3722,7 @@ class DocSearch {
              * @returns {AsyncGenerator<rustdoc.ResultObject>}
              */
             async function*(currentCrate) {
-                const index = this.database.getIndex("normalizedName");
+                const index = this.database.getData("normalizedName");
                 if (!index) {
                     return;
                 }
@@ -3851,8 +3851,7 @@ class DocSearch {
                 };
                 if (elem.normalizedPathLast === "") {
                     // faster full-table scan for this specific case.
-                    const nameData = this.database.getData("name");
-                    const l = nameData ? nameData.length : 0;
+                    const l = index.length;
                     for (let id = 0; id < l; ++id) {
                         if (!idDuplicates.has(id)) {
                             idDuplicates.add(id);
@@ -3954,7 +3953,7 @@ class DocSearch {
              * @returns {AsyncGenerator<rustdoc.ResultObject>}
              */
             async function*(inputs, output, typeInfo, currentCrate) {
-                const index = this.database.getIndex("normalizedName");
+                const index = this.database.getData("normalizedName");
                 if (!index) {
                     return;
                 }
diff --git a/src/librustdoc/html/static/js/stringdex.d.ts b/src/librustdoc/html/static/js/stringdex.d.ts
index cf9a8b6b564..2eb1fdf95d8 100644
--- a/src/librustdoc/html/static/js/stringdex.d.ts
+++ b/src/librustdoc/html/static/js/stringdex.d.ts
@@ -5,18 +5,9 @@ declare namespace stringdex {
      * The client interface to Stringdex.
      */
     interface Database {
-        getIndex(colname: string): SearchTree|undefined;
         getData(colname: string): DataColumn|undefined;
     }
     /**
-     * A search index file.
-     */
-    interface SearchTree {
-        trie(): Trie;
-        search(name: Uint8Array|string): Promise<Trie?>;
-        searchLev(name: Uint8Array|string): AsyncGenerator<Trie>;
-    }
-    /**
      * A compressed node in the search tree.
      *
      * This object logically addresses two interleaved trees:
@@ -29,9 +20,7 @@ declare namespace stringdex {
         matches(): RoaringBitmap;
         substringMatches(): AsyncGenerator<RoaringBitmap>;
         prefixMatches(): AsyncGenerator<RoaringBitmap>;
-        keys(): Uint8Array;
         keysExcludeSuffixOnly(): Uint8Array;
-        children(): [number, Promise<Trie>][];
         childrenExcludeSuffixOnly(): [number, Promise<Trie>][];
         child(id: number): Promise<Trie>?;
     }
@@ -41,6 +30,8 @@ declare namespace stringdex {
     interface DataColumn {
         isEmpty(id: number): boolean;
         at(id: number): Promise<Uint8Array|undefined>;
+        search(name: Uint8Array|string): Promise<Trie?>;
+        searchLev(name: Uint8Array|string): AsyncGenerator<Trie>;
         length: number,
     }
     /**
diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js
index cb956d926db..b7f605a1035 100644
--- a/src/librustdoc/html/static/js/stringdex.js
+++ b/src/librustdoc/html/static/js/stringdex.js
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 /**
  * @import * as stringdex from "./stringdex.d.ts"
  */
@@ -486,6 +487,63 @@ class RoaringBitmap {
         return mid === -1 ? false : this.containers[mid].contains(value);
     }
     /**
+     * @param {number} keyvalue
+     * @returns {RoaringBitmap}
+     */
+    remove(keyvalue) {
+        const key = keyvalue >> 16;
+        const value = keyvalue & 0xFFFF;
+        const mid = this.getContainerId(key);
+        if (mid === -1) {
+            return this;
+        }
+        const container = this.containers[mid];
+        if (!container.contains(value)) {
+            return this;
+        }
+        const newCardinality = (this.keysAndCardinalities[(mid * 4) + 2] |
+            (this.keysAndCardinalities[(mid * 4) + 3] << 8));
+        const l = this.containers.length;
+        const m = l - (newCardinality === 0 ? 1 : 0);
+        const result = new RoaringBitmap(null, 0);
+        result.keysAndCardinalities = new Uint8Array(m * 4);
+        let j = 0;
+        for (let i = 0; i < l; i += 1) {
+            if (i === mid) {
+                if (newCardinality !== 0) {
+                    result.keysAndCardinalities[(j * 4) + 0] = key;
+                    result.keysAndCardinalities[(j * 4) + 1] = key >> 8;
+                    const card = newCardinality - 1;
+                    result.keysAndCardinalities[(j * 4) + 2] = card;
+                    result.keysAndCardinalities[(j * 4) + 3] = card >> 8;
+                    const newContainer = new RoaringBitmapArray(
+                        newCardinality,
+                        new Uint8Array(newCardinality * 2),
+                    );
+                    let newContainerSlot = 0;
+                    for (const containerValue of container.values()) {
+                        if (containerValue !== value) {
+                            newContainer.array[newContainerSlot] = value & 0xFF;
+                            newContainerSlot += 1;
+                            newContainer.array[newContainerSlot] = value >> 8;
+                            newContainerSlot += 1;
+                        }
+                    }
+                    result.containers.push(newContainer);
+                    j += 1;
+                }
+            } else {
+                result.keysAndCardinalities[(j * 4) + 0] = this.keysAndCardinalities[(i * 4) + 0];
+                result.keysAndCardinalities[(j * 4) + 1] = this.keysAndCardinalities[(i * 4) + 1];
+                result.keysAndCardinalities[(j * 4) + 2] = this.keysAndCardinalities[(i * 4) + 2];
+                result.keysAndCardinalities[(j * 4) + 3] = this.keysAndCardinalities[(i * 4) + 3];
+                result.containers.push(this.containers[i]);
+                j += 1;
+            }
+        }
+        return result;
+    }
+    /**
      * @param {number} key
      * @returns {number}
      */
@@ -878,6 +936,46 @@ function bitCount(n) {
 /*eslint-enable */
 
 /**
+ * https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm
+ */
+class Uint8ArraySearchPattern {
+    /** @param {Uint8Array} needle */
+    constructor(needle) {
+        this.needle = needle;
+        this.skipTable = [];
+        const m = needle.length;
+        for (let i = 0; i < 256; i += 1) {
+            this.skipTable.push(m);
+        }
+        for (let i = 0; i < m - 1; i += 1) {
+            this.skipTable[needle[i]] = m - 1 - i;
+        }
+    }
+    /**
+     * @param {Uint8Array} haystack
+     * @returns {boolean}
+     */
+    matches(haystack) {
+        const needle = this.needle;
+        const skipTable = this.skipTable;
+        const m = needle.length;
+        const n = haystack.length;
+
+        let skip = 0;
+        search: while (n - skip >= m) {
+            for (let i = m - 1; i >= 0; i -= 1) {
+                if (haystack[skip + i] !== needle[i]) {
+                    skip += skipTable[haystack[skip + m  - 1]];
+                    continue search;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+}
+
+/**
  * @param {stringdex.Hooks} hooks
  * @returns {Promise<stringdex.Database>}
  */
@@ -887,12 +985,6 @@ function loadDatabase(hooks) {
         rr_: function(data) {
             const dataObj = JSON.parse(data);
             for (const colName of Object.keys(dataObj)) {
-                if (Object.hasOwn(dataObj[colName], "I")) {
-                    registry.searchTreeRoots.set(
-                        colName,
-                        makeSearchTreeFromBase64(dataObj[colName].I)[1],
-                    );
-                }
                 if (Object.hasOwn(dataObj[colName], "N")) {
                     const counts = [];
                     const countsstring = dataObj[colName]["N"];
@@ -915,6 +1007,9 @@ function loadDatabase(hooks) {
                         makeUint8ArrayFromBase64(dataObj[colName]["H"]),
                         new RoaringBitmap(makeUint8ArrayFromBase64(dataObj[colName]["E"]), 0),
                         colName,
+                        Object.hasOwn(dataObj[colName], "I") ?
+                            makeSearchTreeFromBase64(dataObj[colName].I)[1] :
+                            null,
                     ));
                 }
             }
@@ -978,7 +1073,7 @@ function loadDatabase(hooks) {
      *      searchTreePromises: HashTable<Promise<SearchTree>>;
      *      dataColumnLoadPromiseCallbacks: HashTable<function(any, Uint8Array[]?): any>;
      *      dataColumns: Map<string, DataColumn>;
-     *      dataColumnsBuckets: Map<string, HashTable<Promise<Uint8Array[]>>>;
+     *      dataColumnsBuckets: HashTable<Promise<Uint8Array[]>>;
      *      searchTreeLoadByNodeID: function(Uint8Array): Promise<SearchTree>;
      *      searchTreeRootCallback?: function(any, Database?): any;
      *      dataLoadByNameAndHash: function(string, Uint8Array): Promise<Uint8Array[]>;
@@ -990,7 +1085,7 @@ function loadDatabase(hooks) {
         searchTreePromises: new HashTable(),
         dataColumnLoadPromiseCallbacks: new HashTable(),
         dataColumns: new Map(),
-        dataColumnsBuckets: new Map(),
+        dataColumnsBuckets: new HashTable(),
         searchTreeLoadByNodeID: function(nodeid) {
             const existingPromise = registry.searchTreePromises.get(nodeid);
             if (existingPromise) {
@@ -1022,7 +1117,7 @@ function loadDatabase(hooks) {
                 const data = (nodeid[0] & 0x20) !== 0 ?
                     Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
                     EMPTY_UINT8;
-                newPromise = Promise.resolve(new SearchTree(
+                newPromise = Promise.resolve(new PrefixSearchTree(
                     EMPTY_SEARCH_TREE_BRANCHES,
                     EMPTY_SEARCH_TREE_BRANCHES,
                     data,
@@ -1058,12 +1153,7 @@ function loadDatabase(hooks) {
             return newPromise;
         },
         dataLoadByNameAndHash: function(name, hash) {
-            let dataColumnBuckets = registry.dataColumnsBuckets.get(name);
-            if (dataColumnBuckets === undefined) {
-                dataColumnBuckets = new HashTable();
-                registry.dataColumnsBuckets.set(name, dataColumnBuckets);
-            }
-            const existingBucket = dataColumnBuckets.get(hash);
+            const existingBucket = registry.dataColumnsBuckets.get(hash);
             if (existingBucket) {
                 return existingBucket;
             }
@@ -1091,16 +1181,17 @@ function loadDatabase(hooks) {
                     hooks.loadDataByNameAndHash(name, hashHex);
                 }
             });
-            dataColumnBuckets.set(hash, newBucket);
+            registry.dataColumnsBuckets.set(hash, newBucket);
             return newBucket;
         },
     };
 
     /**
      * The set of child subtrees.
+     * @template ST
      * @type {{
      *    nodeids: Uint8Array,
-     *    subtrees: Array<Promise<SearchTree>|null>,
+     *    subtrees: Array<Promise<ST>|null>,
      * }}
      */
     class SearchTreeBranches {
@@ -1128,7 +1219,7 @@ function loadDatabase(hooks) {
             );
         }
         // https://github.com/microsoft/TypeScript/issues/17227
-        /** @returns {Generator<[number, Promise<SearchTree>|null]>} */
+        /** @returns {Generator<[number, Promise<ST>|null]>} */
         entries() {
             throw new Error();
         }
@@ -1157,10 +1248,12 @@ function loadDatabase(hooks) {
     /**
      * A sorted array of search tree branches.
      *
+     * @template ST
+     * @extends SearchTreeBranches<ST>
      * @type {{
      *    keys: Uint8Array,
      *    nodeids: Uint8Array,
-     *    subtrees: Array<Promise<SearchTree>|null>,
+     *    subtrees: Array<Promise<ST>|null>,
      * }}
      */
     class SearchTreeBranchesArray extends SearchTreeBranches {
@@ -1179,7 +1272,7 @@ function loadDatabase(hooks) {
                 i += 1;
             }
         }
-        /** @returns {Generator<[number, Promise<SearchTree>|null]>} */
+        /** @returns {Generator<[number, Promise<ST>|null]>} */
         * entries() {
             let i = 0;
             const l = this.keys.length;
@@ -1246,12 +1339,16 @@ function loadDatabase(hooks) {
     }
 
     /**
+     * @template ST
      * @param {number[]} alphabitmap_chars
      * @param {number} width
-     * @return {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}}
+     * @return {(typeof SearchTreeBranches<ST>)&{"ALPHABITMAP_CHARS": number[], "width": number}}
      */
     function makeSearchTreeBranchesAlphaBitmapClass(alphabitmap_chars, width) {
         const bitwidth = width * 8;
+        /**
+         * @extends SearchTreeBranches<ST>
+         */
         const cls = class SearchTreeBranchesAlphaBitmap extends SearchTreeBranches {
             /**
              * @param {number} bitmap
@@ -1265,7 +1362,7 @@ function loadDatabase(hooks) {
                 this.bitmap = bitmap;
                 this.nodeids = nodeids;
             }
-            /** @returns {Generator<[number, Promise<SearchTree>|null]>} */
+            /** @returns {Generator<[number, Promise<ST>|null]>} */
             * entries() {
                 let i = 0;
                 let j = 0;
@@ -1295,15 +1392,7 @@ function loadDatabase(hooks) {
              * @returns {number}
              */
             getKey(branch_index) {
-                //return this.getKeys()[branch_index];
-                let alpha_index = 0;
-                while (branch_index >= 0) {
-                    if (this.bitmap & (1 << alpha_index)) {
-                        branch_index -= 1;
-                    }
-                    alpha_index += 1;
-                }
-                return alphabitmap_chars[alpha_index];
+                return this.getKeys()[branch_index];
             }
             /**
              * @returns {Uint8Array}
@@ -1326,20 +1415,35 @@ function loadDatabase(hooks) {
         return cls;
     }
 
+    /**
+     * @template ST
+     * @type {(typeof SearchTreeBranches<any>)&{"ALPHABITMAP_CHARS": number[], "width": number}}
+     */
     const SearchTreeBranchesShortAlphaBitmap =
         makeSearchTreeBranchesAlphaBitmapClass(SHORT_ALPHABITMAP_CHARS, 3);
 
+    /**
+     * @template ST
+     * @type {(typeof SearchTreeBranches<any>)&{"ALPHABITMAP_CHARS": number[], "width": number}}
+     */
     const SearchTreeBranchesLongAlphaBitmap =
         makeSearchTreeBranchesAlphaBitmapClass(LONG_ALPHABITMAP_CHARS, 4);
 
     /**
-     * A [suffix tree], used for name-based search.
+     * @typedef {PrefixSearchTree|SuffixSearchTree} SearchTree
+     * @typedef {PrefixTrie|SuffixTrie} Trie
+     */
+
+    /**
+     * An interleaved [prefix] and [suffix tree],
+     * used for name-based search.
      *
-     * This data structure is used to drive substring matches,
+     * This data structure is used to drive prefix matches,
      * such as matching the query "link" to `LinkedList`,
      * and Lev-distance matches, such as matching the
      * query "hahsmap" to `HashMap`.
      *
+     * [prefix tree]: https://en.wikipedia.org/wiki/Prefix_tree
      * [suffix tree]: https://en.wikipedia.org/wiki/Suffix_tree
      *
      * branches
@@ -1358,17 +1462,17 @@ function loadDatabase(hooks) {
      *   will include these.
      *
      * @type {{
-     *     might_have_prefix_branches: SearchTreeBranches,
-     *     branches: SearchTreeBranches,
+     *     might_have_prefix_branches: SearchTreeBranches<SearchTree>,
+     *     branches: SearchTreeBranches<SearchTree>,
      *     data: Uint8Array,
      *     leaves_suffix: RoaringBitmap,
      *     leaves_whole: RoaringBitmap,
      * }}
      */
-    class SearchTree {
+    class PrefixSearchTree {
         /**
-         * @param {SearchTreeBranches} branches
-         * @param {SearchTreeBranches} might_have_prefix_branches
+         * @param {SearchTreeBranches<SearchTree>} branches
+         * @param {SearchTreeBranches<SearchTree>} might_have_prefix_branches
          * @param {Uint8Array} data
          * @param {RoaringBitmap} leaves_whole
          * @param {RoaringBitmap} leaves_suffix
@@ -1392,25 +1496,31 @@ function loadDatabase(hooks) {
          * A Trie pointer refers to a single node in a logical decompressed search tree
          * (the real search tree is compressed).
          *
-         * @return {Trie}
+         * @param {DataColumn} dataColumn
+         * @param {Uint8ArraySearchPattern} searchPattern
+         * @return {PrefixTrie}
          */
-        trie() {
-            return new Trie(this, 0);
+        trie(dataColumn, searchPattern) {
+            return new PrefixTrie(this, 0, dataColumn, searchPattern);
         }
 
         /**
          * Return the trie representing `name`
          * @param {Uint8Array|string} name
+         * @param {DataColumn} dataColumn
          * @returns {Promise<Trie?>}
          */
-        async search(name) {
+        async search(name, dataColumn) {
             if (typeof name === "string") {
                 const utf8encoder = new TextEncoder();
                 name = utf8encoder.encode(name);
             }
-            let trie = this.trie();
+            const searchPattern = new Uint8ArraySearchPattern(name);
+            /** @type {Trie} */
+            let trie = this.trie(dataColumn, searchPattern);
             for (const datum of name) {
                 // code point definitely exists
+                /** @type {Promise<Trie>?} */
                 const newTrie = trie.child(datum);
                 if (newTrie) {
                     trie = await newTrie;
@@ -1423,26 +1533,28 @@ function loadDatabase(hooks) {
 
         /**
          * @param {Uint8Array|string} name
+         * @param {DataColumn} dataColumn
          * @returns {AsyncGenerator<Trie>}
          */
-        async* searchLev(name) {
+        async* searchLev(name, dataColumn) {
             if (typeof name === "string") {
                 const utf8encoder = new TextEncoder();
                 name = utf8encoder.encode(name);
             }
             const w = name.length;
             if (w < 3) {
-                const trie = await this.search(name);
+                const trie = await this.search(name, dataColumn);
                 if (trie !== null) {
                     yield trie;
                 }
                 return;
             }
+            const searchPattern = new Uint8ArraySearchPattern(name);
             const levParams = w >= 6 ?
                 new Lev2TParametricDescription(w) :
                 new Lev1TParametricDescription(w);
             /** @type {Array<[Promise<Trie>, number]>} */
-            const stack = [[Promise.resolve(this.trie()), 0]];
+            const stack = [[Promise.resolve(this.trie(dataColumn, searchPattern)), 0]];
             const n = levParams.n;
             while (stack.length !== 0) {
                 // It's not empty
@@ -1475,20 +1587,29 @@ function loadDatabase(hooks) {
                 }
             }
         }
+
+        /** @returns {RoaringBitmap} */
+        getCurrentLeaves() {
+            return this.leaves_whole.union(this.leaves_suffix);
+        }
     }
 
     /**
      * A representation of a set of strings in the search index,
      * as a subset of the entire tree.
      */
-    class Trie {
+    class PrefixTrie {
         /**
-         * @param {SearchTree} tree
+         * @param {PrefixSearchTree} tree
          * @param {number} offset
+         * @param {DataColumn} dataColumn
+         * @param {Uint8ArraySearchPattern} searchPattern
          */
-        constructor(tree, offset) {
+        constructor(tree, offset, dataColumn, searchPattern) {
             this.tree = tree;
             this.offset = offset;
+            this.dataColumn = dataColumn;
+            this.searchPattern = searchPattern;
         }
 
         /**
@@ -1514,7 +1635,28 @@ function loadDatabase(hooks) {
                 const current_layer = layer;
                 layer = [];
                 for await (const tree of current_layer) {
-                    yield tree.leaves_whole.union(tree.leaves_suffix);
+                    /** @type {number[]?} */
+                    let rejected = null;
+                    let leaves = tree.getCurrentLeaves();
+                    for (const leaf of leaves.entries()) {
+                        const haystack = await this.dataColumn.at(leaf);
+                        if (haystack === undefined || !this.searchPattern.matches(haystack)) {
+                            if (!rejected) {
+                                rejected = [];
+                            }
+                            rejected.push(leaf);
+                        }
+                    }
+                    if (rejected) {
+                        if (leaves.cardinality() !== rejected.length) {
+                            for (const rej of rejected) {
+                                leaves = leaves.remove(rej);
+                            }
+                            yield leaves;
+                        }
+                    } else {
+                        yield leaves;
+                    }
                 }
                 /** @type {HashTable<[number, SearchTree][]>} */
                 const subnodes = new HashTable();
@@ -1548,12 +1690,14 @@ function loadDatabase(hooks) {
                     const res = registry.searchTreeLoadByNodeID(newnode);
                     for (const [byte, node] of subnode_list) {
                         const branches = node.branches;
-                        const might_have_prefix_branches = node.might_have_prefix_branches;
                         const i = branches.getIndex(byte);
                         branches.subtrees[i] = res;
-                        const mhpI = might_have_prefix_branches.getIndex(byte);
-                        if (mhpI !== -1) {
-                            might_have_prefix_branches.subtrees[mhpI] = res;
+                        if (node instanceof PrefixSearchTree) {
+                            const might_have_prefix_branches = node.might_have_prefix_branches;
+                            const mhpI = might_have_prefix_branches.getIndex(byte);
+                            if (mhpI !== -1) {
+                                might_have_prefix_branches.subtrees[mhpI] = res;
+                            }
                         }
                     }
                     layer.push(res);
@@ -1581,6 +1725,9 @@ function loadDatabase(hooks) {
                 // if we want to do them in order)
                 for (const {node, len} of current_layer) {
                     const tree = await node;
+                    if (!(tree instanceof PrefixSearchTree)) {
+                        continue;
+                    }
                     const length = len + tree.data.length;
                     if (minLength === null || length < minLength) {
                         minLength = length;
@@ -1637,10 +1784,13 @@ function loadDatabase(hooks) {
                     }
                 }
                 // if we still have more subtrees to walk, then keep going
-                /** @type {HashTable<{byte: number, tree: SearchTree, len: number}[]>} */
+                /** @type {HashTable<{byte: number, tree: PrefixSearchTree, len: number}[]>} */
                 const subnodes = new HashTable();
                 for await (const {node, len} of current_layer) {
                     const tree = await node;
+                    if (!(tree instanceof PrefixSearchTree)) {
+                        continue;
+                    }
                     const length = len + tree.data.length;
                     const mhp_branches = tree.might_have_prefix_branches;
                     const l = mhp_branches.subtrees.length;
@@ -1663,8 +1813,6 @@ function loadDatabase(hooks) {
                                     subnode_list.push({byte, tree, len});
                                 }
                             }
-                        } else {
-                            throw new Error(`malformed tree; index ${i} does not exist`);
                         }
                     }
                 }
@@ -1728,14 +1876,21 @@ function loadDatabase(hooks) {
                             this.tree.might_have_prefix_branches.subtrees[mhpI] = node;
                         }
                     }
-                    nodes.push([k, node.then(node => node.trie())]);
+                    nodes.push([k, node.then(node => {
+                        return node.trie(this.dataColumn, this.searchPattern);
+                    })]);
                     i += 1;
                 }
                 return nodes;
             } else {
                 /** @type {number} */
                 const codePoint = data[this.offset];
-                const trie = new Trie(this.tree, this.offset + 1);
+                const trie = new PrefixTrie(
+                    this.tree,
+                    this.offset + 1,
+                    this.dataColumn,
+                    this.searchPattern,
+                );
                 return [[codePoint, Promise.resolve(trie)]];
             }
         }
@@ -1777,14 +1932,21 @@ function loadDatabase(hooks) {
                         this.tree.might_have_prefix_branches.subtrees[i] = node;
                         this.tree.branches.subtrees[this.tree.branches.getIndex(k)] = node;
                     }
-                    nodes.push([k, node.then(node => node.trie())]);
+                    nodes.push([k, node.then(node => {
+                        return node.trie(this.dataColumn, this.searchPattern);
+                    })]);
                     i += 1;
                 }
                 return nodes;
             } else {
                 /** @type {number} */
                 const codePoint = data[this.offset];
-                const trie = new Trie(this.tree, this.offset + 1);
+                const trie = new PrefixTrie(
+                    this.tree,
+                    this.offset + 1,
+                    this.dataColumn,
+                    this.searchPattern,
+                );
                 return [[codePoint, Promise.resolve(trie)]];
             }
         }
@@ -1811,10 +1973,275 @@ function loadDatabase(hooks) {
                             this.tree.might_have_prefix_branches.subtrees[mhpI] = branch;
                         }
                     }
-                    return branch.then(branch => branch.trie());
+                    return branch.then(branch => branch.trie(this.dataColumn, this.searchPattern));
                 }
             } else if (this.tree.data[this.offset] === byte) {
-                return Promise.resolve(new Trie(this.tree, this.offset + 1));
+                return Promise.resolve(new PrefixTrie(
+                    this.tree,
+                    this.offset + 1,
+                    this.dataColumn,
+                    this.searchPattern,
+                ));
+            }
+            return null;
+        }
+    }
+    /**
+     * A [suffix tree], used for name-based search.
+     *
+     * This data structure is used to drive substring matches,
+     * such as matching the query "inked" to `LinkedList`.
+     *
+     * [suffix tree]: https://en.wikipedia.org/wiki/Suffix_tree
+     *
+     * Suffix trees do not actually carry the intermediate data
+     * between branches, so, in order to validate the results,
+     * they must go through a filtering step at the end.
+     * Suffix trees also cannot match lev and exact matches,
+     * so those just return empty sets.
+     *
+     * branches
+     * : A sorted-array map of subtrees.
+     *
+     * dataLen
+     * : The length of the substring used by this node.
+     *
+     * leaves_suffix
+     * : The IDs of every entry that matches. Levenshtein matches
+     *   won't include these.
+     *
+     * @type {{
+     *     branches: SearchTreeBranches<SearchTree>,
+     *     dataLen: number,
+     *     leaves_suffix: RoaringBitmap,
+     * }}
+     */
+    class SuffixSearchTree {
+        /**
+         * @param {SearchTreeBranches<SearchTree>} branches
+         * @param {number} dataLen
+         * @param {RoaringBitmap} leaves_suffix
+         */
+        constructor(
+            branches,
+            dataLen,
+            leaves_suffix,
+        ) {
+            this.branches = branches;
+            this.dataLen = dataLen;
+            this.leaves_suffix = leaves_suffix;
+        }
+        /**
+         * Returns the Trie for the root node.
+         *
+         * A Trie pointer refers to a single node in a logical decompressed search tree
+         * (the real search tree is compressed).
+         *
+         * @param {DataColumn} dataColumn
+         * @param {Uint8ArraySearchPattern} searchPattern
+         * @return {Trie}
+         */
+        trie(dataColumn, searchPattern) {
+            return new SuffixTrie(this, 0, dataColumn, searchPattern);
+        }
+
+        /**
+         * Return the trie representing `name`
+         * @param {Uint8Array|string} name
+         * @param {DataColumn} dataColumn
+         * @returns {Promise<Trie?>}
+         */
+        async search(name, dataColumn) {
+            if (typeof name === "string") {
+                const utf8encoder = new TextEncoder();
+                name = utf8encoder.encode(name);
+            }
+            const searchPattern = new Uint8ArraySearchPattern(name);
+            let trie = this.trie(dataColumn, searchPattern);
+            for (const datum of name) {
+                // code point definitely exists
+                const newTrie = trie.child(datum);
+                if (newTrie) {
+                    trie = await newTrie;
+                } else {
+                    return null;
+                }
+            }
+            return trie;
+        }
+
+        /**
+         * @param {Uint8Array|string} _name
+         * @param {DataColumn} _dataColumn
+         * @returns {AsyncGenerator<Trie>}
+         */
+        async* searchLev(_name, _dataColumn) {
+            // this function only returns whole-string matches,
+            // which pure-suffix nodes don't have, so is
+            // intentionally blank
+        }
+
+        /** @returns {RoaringBitmap} */
+        getCurrentLeaves() {
+            return this.leaves_suffix;
+        }
+    }
+
+    /**
+     * A representation of a set of strings in the search index,
+     * as a subset of the entire tree (suffix-only).
+     */
+    class SuffixTrie {
+        /**
+         * @param {SuffixSearchTree} tree
+         * @param {number} offset
+         * @param {DataColumn} dataColumn
+         * @param {Uint8ArraySearchPattern} searchPattern
+         */
+        constructor(tree, offset, dataColumn, searchPattern) {
+            this.tree = tree;
+            this.offset = offset;
+            this.dataColumn = dataColumn;
+            this.searchPattern = searchPattern;
+        }
+
+        /**
+         * All exact matches for the string represented by this node.
+         * Since pure-suffix nodes have no exactly-matching children,
+         * this function returns the empty bitmap.
+         * @returns {RoaringBitmap}
+         */
+        matches() {
+            return EMPTY_BITMAP;
+        }
+
+        /**
+         * All matches for strings that contain the string represented by this node.
+         * @returns {AsyncGenerator<RoaringBitmap>}
+         */
+        async* substringMatches() {
+            /** @type {Promise<SearchTree>[]} */
+            let layer = [Promise.resolve(this.tree)];
+            while (layer.length) {
+                const current_layer = layer;
+                layer = [];
+                for await (const tree of current_layer) {
+                    /** @type {number[]?} */
+                    let rejected = null;
+                    let leaves = tree.getCurrentLeaves();
+                    for (const leaf of leaves.entries()) {
+                        const haystack = await this.dataColumn.at(leaf);
+                        if (haystack === undefined || !this.searchPattern.matches(haystack)) {
+                            if (!rejected) {
+                                rejected = [];
+                            }
+                            rejected.push(leaf);
+                        }
+                    }
+                    if (rejected) {
+                        if (leaves.cardinality() !== rejected.length) {
+                            for (const rej of rejected) {
+                                leaves = leaves.remove(rej);
+                            }
+                            yield leaves;
+                        }
+                    } else {
+                        yield leaves;
+                    }
+                }
+                /** @type {HashTable<[number, SearchTree][]>} */
+                const subnodes = new HashTable();
+                for await (const node of current_layer) {
+                    const branches = node.branches;
+                    const l = branches.subtrees.length;
+                    for (let i = 0; i < l; ++i) {
+                        const subtree = branches.subtrees[i];
+                        if (subtree) {
+                            layer.push(subtree);
+                        } else if (subtree === null) {
+                            const newnode = branches.getNodeID(i);
+                            if (!newnode) {
+                                throw new Error(`malformed tree; no node for index ${i}`);
+                            } else {
+                                let subnode_list = subnodes.get(newnode);
+                                if (!subnode_list) {
+                                    subnode_list = [[i, node]];
+                                    subnodes.set(newnode, subnode_list);
+                                } else {
+                                    subnode_list.push([i, node]);
+                                }
+                            }
+                        } else {
+                            throw new Error(`malformed tree; index ${i} does not exist`);
+                        }
+                    }
+                }
+                for (const [newnode, subnode_list] of subnodes.entries()) {
+                    const res = registry.searchTreeLoadByNodeID(newnode);
+                    for (const [i, node] of subnode_list) {
+                        const branches = node.branches;
+                        branches.subtrees[i] = res;
+                    }
+                    layer.push(res);
+                }
+            }
+        }
+
+        /**
+         * All matches for strings that start with the string represented by this node.
+         * Since this is a pure-suffix node, there aren't any.
+         * @returns {AsyncGenerator<RoaringBitmap>}
+         */
+        async* prefixMatches() {
+            // this function only returns prefix matches,
+            // which pure-suffix nodes don't have, so is
+            // intentionally blank
+        }
+
+        /**
+         * Returns all keys that are children of this node.
+         * @returns {Uint8Array}
+         */
+        keysExcludeSuffixOnly() {
+            return EMPTY_UINT8;
+        }
+
+        /**
+         * Returns all nodes that are direct children of this node.
+         * @returns {[number, Promise<Trie>][]}
+         */
+        childrenExcludeSuffixOnly() {
+            return [];
+        }
+
+        /**
+         * Returns a single node that is a direct child of this node.
+         * @param {number} byte
+         * @returns {Promise<Trie>?}
+         */
+        child(byte) {
+            if (this.offset === this.tree.dataLen) {
+                const i = this.tree.branches.getIndex(byte);
+                if (i !== -1) {
+                    /** @type {Promise<SearchTree>?} */
+                    let branch = this.tree.branches.subtrees[i];
+                    if (branch === null) {
+                        const newnode = this.tree.branches.getNodeID(i);
+                        if (!newnode) {
+                            throw new Error(`malformed tree; no node for key ${byte}`);
+                        }
+                        branch = registry.searchTreeLoadByNodeID(newnode);
+                        this.tree.branches.subtrees[i] = branch;
+                    }
+                    return branch.then(branch => branch.trie(this.dataColumn, this.searchPattern));
+                }
+            } else {
+                return Promise.resolve(new SuffixTrie(
+                    this.tree,
+                    this.offset + 1,
+                    this.dataColumn,
+                    this.searchPattern,
+                ));
             }
             return null;
         }
@@ -1827,8 +2254,10 @@ function loadDatabase(hooks) {
          * @param {Uint8Array} hashes
          * @param {RoaringBitmap} emptyset
          * @param {string} name
+         * @param {SearchTree?} searchTree
          */
-        constructor(counts, hashes, emptyset, name) {
+        constructor(counts, hashes, emptyset, name, searchTree) {
+            this.searchTree = searchTree;
             this.hashes = hashes;
             this.emptyset = emptyset;
             this.name = name;
@@ -1883,7 +2312,7 @@ function loadDatabase(hooks) {
                     const {hash, end} = this.buckets[idx];
                     let data = this.buckets[idx].data;
                     if (data === null) {
-                        const dataSansEmptyset = await registry.dataLoadByNameAndHash(
+                        const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash(
                             this.name,
                             hash,
                         );
@@ -1893,6 +2322,7 @@ function loadDatabase(hooks) {
                         if (data !== null) {
                             return (await data)[id - start];
                         }
+                        const dataSansEmptyset = [...dataSansEmptysetOrig];
                         /** @type {(Uint8Array[])|null} */
                         let dataWithEmptyset = null;
                         let pos = start;
@@ -1924,6 +2354,24 @@ function loadDatabase(hooks) {
                 }
             }
         }
+        /**
+         * Search by exact substring
+         * @param {Uint8Array|string} name
+         * @returns {Promise<Trie?>}
+         */
+        async search(name) {
+            return await (this.searchTree ? this.searchTree.search(name, this) : null);
+        }
+        /**
+         * Search by whole, inexact match
+         * @param {Uint8Array|string} name
+         * @returns {AsyncGenerator<Trie>}
+         */
+        async *searchLev(name) {
+            if (this.searchTree) {
+                yield* this.searchTree.searchLev(name, this);
+            }
+        }
     }
 
     class Database {
@@ -2015,7 +2463,7 @@ function loadDatabase(hooks) {
         const data_history = [];
         let canonical = EMPTY_UINT8;
         /** @type {SearchTree} */
-        let tree = new SearchTree(
+        let tree = new PrefixSearchTree(
             EMPTY_SEARCH_TREE_BRANCHES,
             EMPTY_SEARCH_TREE_BRANCHES,
             EMPTY_UINT8,
@@ -2029,8 +2477,8 @@ function loadDatabase(hooks) {
          * @returns {{
          *     "cpbranches": Uint8Array,
          *     "csbranches": Uint8Array,
-         *     "might_have_prefix_branches": SearchTreeBranches,
-         *     "branches": SearchTreeBranches,
+         *     "might_have_prefix_branches": SearchTreeBranches<SearchTree>,
+         *     "branches": SearchTreeBranches<SearchTree>,
          *     "cpnodes": Uint8Array,
          *     "csnodes": Uint8Array,
          *     "consumed_len_bytes": number,
@@ -2051,6 +2499,12 @@ function loadDatabase(hooks) {
             const start_point = i;
             let cplen;
             let cslen;
+            /**
+             * @type {(
+             *   typeof SearchTreeBranches<SearchTree> &
+             *   {"ALPHABITMAP_CHARS": number[], "width": number}
+             * )?}
+             */
             let alphabitmap = null;
             if (is_pure_suffixes_only_node) {
                 cplen = 0;
@@ -2299,6 +2753,8 @@ function loadDatabase(hooks) {
                 if (is_data_compressed) {
                     data = data_history[data_history.length - dlen - 1];
                     dlen = data.length;
+                } else if (is_pure_suffixes_only_node) {
+                    data = EMPTY_UINT8;
                 } else {
                     data = dlen === 0 ?
                         EMPTY_UINT8 :
@@ -2319,80 +2775,109 @@ function loadDatabase(hooks) {
                 let whole;
                 let suffix;
                 if (is_pure_suffixes_only_node) {
-                    whole = EMPTY_BITMAP;
                     suffix = input[i] === 0 ?
                         EMPTY_BITMAP1 :
                         new RoaringBitmap(input, i);
                     i += suffix.consumed_len_bytes;
-                } else if (input[i] === 0xff) {
-                    whole = EMPTY_BITMAP;
-                    suffix = EMPTY_BITMAP1;
-                    i += 1;
+                    tree = new SuffixSearchTree(
+                        branches,
+                        dlen,
+                        suffix,
+                    );
+                    const clen = (
+                        3 + // lengths of children and data
+                        csnodes.length +
+                        csbranches.length +
+                        suffix.consumed_len_bytes
+                    );
+                    if (canonical.length < clen) {
+                        canonical = new Uint8Array(clen);
+                    }
+                    let ci = 0;
+                    canonical[ci] = 1;
+                    ci += 1;
+                    canonical[ci] = dlen;
+                    ci += 1;
+                    canonical[ci] = input[coffset]; // suffix child count
+                    ci += 1;
+                    canonical.set(csnodes, ci);
+                    ci += csnodes.length;
+                    canonical.set(csbranches, ci);
+                    ci += csbranches.length;
+                    const leavesOffset = i - suffix.consumed_len_bytes;
+                    for (let j = leavesOffset; j < i; j += 1) {
+                        canonical[ci + j - leavesOffset] = input[j];
+                    }
+                    siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 } else {
-                    whole = input[i] === 0 ?
-                        EMPTY_BITMAP1 :
-                        new RoaringBitmap(input, i);
-                    i += whole.consumed_len_bytes;
-                    suffix = input[i] === 0 ?
-                        EMPTY_BITMAP1 :
-                        new RoaringBitmap(input, i);
-                    i += suffix.consumed_len_bytes;
-                }
-                tree = new SearchTree(
-                    branches,
-                    might_have_prefix_branches,
-                    data,
-                    whole,
-                    suffix,
-                );
-                const clen = (
-                    (is_pure_suffixes_only_node ? 3 : 4) + // lengths of children and data
-                    dlen +
-                    cpnodes.length + csnodes.length +
-                    cpbranches.length + csbranches.length +
-                    whole.consumed_len_bytes +
-                    suffix.consumed_len_bytes
-                );
-                if (canonical.length < clen) {
-                    canonical = new Uint8Array(clen);
-                }
-                let ci = 0;
-                canonical[ci] = is_pure_suffixes_only_node ? 1 : 0;
-                ci += 1;
-                canonical[ci] = dlen;
-                ci += 1;
-                canonical.set(data, ci);
-                ci += dlen;
-                canonical[ci] = input[coffset];
-                ci += 1;
-                if (!is_pure_suffixes_only_node) {
-                    canonical[ci] = input[coffset + 1];
+                    if (input[i] === 0xff) {
+                        whole = EMPTY_BITMAP;
+                        suffix = EMPTY_BITMAP1;
+                        i += 1;
+                    } else {
+                        whole = input[i] === 0 ?
+                            EMPTY_BITMAP1 :
+                            new RoaringBitmap(input, i);
+                        i += whole.consumed_len_bytes;
+                        suffix = input[i] === 0 ?
+                            EMPTY_BITMAP1 :
+                            new RoaringBitmap(input, i);
+                        i += suffix.consumed_len_bytes;
+                    }
+                    tree = new PrefixSearchTree(
+                        branches,
+                        might_have_prefix_branches,
+                        data,
+                        whole,
+                        suffix,
+                    );
+                    const clen = (
+                        4 + // lengths of children and data
+                        dlen +
+                        cpnodes.length + csnodes.length +
+                        cpbranches.length + csbranches.length +
+                        whole.consumed_len_bytes +
+                        suffix.consumed_len_bytes
+                    );
+                    if (canonical.length < clen) {
+                        canonical = new Uint8Array(clen);
+                    }
+                    let ci = 0;
+                    canonical[ci] = 0;
                     ci += 1;
+                    canonical[ci] = dlen;
+                    ci += 1;
+                    canonical.set(data, ci);
+                    ci += data.length;
+                    canonical[ci] = input[coffset]; // prefix child count
+                    ci += 1;
+                    canonical[ci] = input[coffset + 1]; // suffix child count
+                    ci += 1;
+                    canonical.set(cpnodes, ci);
+                    ci += cpnodes.length;
+                    canonical.set(csnodes, ci);
+                    ci += csnodes.length;
+                    canonical.set(cpbranches, ci);
+                    ci += cpbranches.length;
+                    canonical.set(csbranches, ci);
+                    ci += csbranches.length;
+                    const leavesOffset = i - whole.consumed_len_bytes - suffix.consumed_len_bytes;
+                    for (let j = leavesOffset; j < i; j += 1) {
+                        canonical[ci + j - leavesOffset] = input[j];
+                    }
+                    siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 }
-                canonical.set(cpnodes, ci);
-                ci += cpnodes.length;
-                canonical.set(csnodes, ci);
-                ci += csnodes.length;
-                canonical.set(cpbranches, ci);
-                ci += cpbranches.length;
-                canonical.set(csbranches, ci);
-                ci += csbranches.length;
-                const leavesOffset = i - whole.consumed_len_bytes - suffix.consumed_len_bytes;
-                for (let j = leavesOffset; j < i; j += 1) {
-                    canonical[ci + j - leavesOffset] = input[j];
-                }
-                siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 hash[2] &= 0x7f;
             } else {
                 // uncompressed node
                 const dlen = input [i + 1];
                 i += 2;
-                if (dlen === 0) {
+                if (dlen === 0 || is_pure_suffixes_only_node) {
                     data = EMPTY_UINT8;
                 } else {
                     data = new Uint8Array(input.buffer, i + input.byteOffset, dlen);
+                    i += dlen;
                 }
-                i += dlen;
                 const {
                     consumed_len_bytes: branches_consumed_len_bytes,
                     branches,
@@ -2427,13 +2912,19 @@ function loadDatabase(hooks) {
                     i - start,
                 ), 0, 0, 0, 0, hash);
                 hash[2] &= 0x7f;
-                tree = new SearchTree(
-                    branches,
-                    might_have_prefix_branches,
-                    data,
-                    whole,
-                    suffix,
-                );
+                tree = is_pure_suffixes_only_node ?
+                    new SuffixSearchTree(
+                        branches,
+                        dlen,
+                        suffix,
+                    ) :
+                    new PrefixSearchTree(
+                        branches,
+                        might_have_prefix_branches,
+                        data,
+                        whole,
+                        suffix,
+                    );
             }
             hash_history.push({hash: truncatedHash.slice(), used: false});
             if (data.length !== 0) {
@@ -2454,20 +2945,22 @@ function loadDatabase(hooks) {
                 }
                 j += 1;
             }
-            const tree_mhp_branch_nodeids = tree.might_have_prefix_branches.nodeids;
-            const tree_mhp_branch_subtrees = tree.might_have_prefix_branches.subtrees;
-            j = 0;
-            lb = tree.might_have_prefix_branches.subtrees.length;
-            while (j < lb) {
-                // node id with a 1 in its most significant bit is inlined, and, so
-                // it won't be in the stash
-                if ((tree_mhp_branch_nodeids[j * 6] & 0x80) === 0) {
-                    const subtree = stash.getWithOffsetKey(tree_mhp_branch_nodeids, j * 6);
-                    if (subtree !== undefined) {
-                        tree_mhp_branch_subtrees[j] = Promise.resolve(subtree);
+            if (tree instanceof PrefixSearchTree) {
+                const tree_mhp_branch_nodeids = tree.might_have_prefix_branches.nodeids;
+                const tree_mhp_branch_subtrees = tree.might_have_prefix_branches.subtrees;
+                j = 0;
+                lb = tree.might_have_prefix_branches.subtrees.length;
+                while (j < lb) {
+                    // node id with a 1 in its most significant bit is inlined, and, so
+                    // it won't be in the stash
+                    if ((tree_mhp_branch_nodeids[j * 6] & 0x80) === 0) {
+                        const subtree = stash.getWithOffsetKey(tree_mhp_branch_nodeids, j * 6);
+                        if (subtree !== undefined) {
+                            tree_mhp_branch_subtrees[j] = Promise.resolve(subtree);
+                        }
                     }
+                    j += 1;
                 }
-                j += 1;
             }
             if (i !== l) {
                 stash.set(truncatedHash, tree);
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 16034c11827..471e966e2c2 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -333,14 +333,11 @@ pub(crate) fn run(
 pub(crate) fn load_call_locations(
     with_examples: Vec<String>,
     dcx: DiagCtxtHandle<'_>,
+    loaded_paths: &mut Vec<PathBuf>,
 ) -> AllCallLocations {
     let mut all_calls: AllCallLocations = FxIndexMap::default();
     for path in with_examples {
-        // FIXME: Figure out why this line is causing this feature to crash in specific contexts.
-        // Full issue backlog is available here: <https://github.com/rust-lang/rust/pull/144600>.
-        //
-        // Can be checked with `tests/run-make/rustdoc-scrape-examples-paths`.
-        // loaded_paths.push(path.clone().into());
+        loaded_paths.push(path.clone().into());
         let bytes = match fs::read(&path) {
             Ok(bytes) => bytes,
             Err(e) => dcx.fatal(format!("failed to load examples: {e}")),
diff --git a/src/stage0 b/src/stage0
index 73bf5ba4b78..a705cd1c760 100644
--- a/src/stage0
+++ b/src/stage0
@@ -15,7 +15,7 @@ nightly_branch=master
 
 compiler_date=2025-08-05
 compiler_version=beta
-rustfmt_date=2025-08-06
+rustfmt_date=2025-09-05
 rustfmt_version=nightly
 
 dist/2025-08-05/rustc-beta-aarch64-apple-darwin.tar.gz=b9d8f74da46aeadb6c650a4ccfc3c2de08e229e4211a198fa2914103f09f579d
@@ -396,123 +396,123 @@ dist/2025-08-05/clippy-beta-x86_64-unknown-linux-musl.tar.gz=79fd42cffac98024308
 dist/2025-08-05/clippy-beta-x86_64-unknown-linux-musl.tar.xz=a3a616554ed25630df9f8cef37a5d36573e6f722b1f6b4220ff4885e2d3a60de
 dist/2025-08-05/clippy-beta-x86_64-unknown-netbsd.tar.gz=ad1849cb72ccfd52ba17a34d90f65226726e5044f7ffbe975c74f23643d87d98
 dist/2025-08-05/clippy-beta-x86_64-unknown-netbsd.tar.xz=608001728598164e234f176d0c6cfe7317dde27fb4cbb8ad1c2452289e83bf30
-dist/2025-08-06/rustfmt-nightly-aarch64-apple-darwin.tar.gz=b33b3bd26dd4518802b325e7c151ea73fa6844bc710ac2d2c8fb55a27c5d7e2a
-dist/2025-08-06/rustfmt-nightly-aarch64-apple-darwin.tar.xz=c900e816a94a0ddd7701c64051ba0e0244c5799e77189e26df109649b10f636f
-dist/2025-08-06/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=aa7c344a52c69ee9b9e68007da806f5741688ce3917c377b6563043703e7d867
-dist/2025-08-06/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=d76d7c6ca6cd5286bee12cabec166a3d8848b28a484a105b56bd5687674bc4c6
-dist/2025-08-06/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=ea4d7c94a12485958b15e7a2782f9b8a09e065c021acd2894e7a905cadfa7489
-dist/2025-08-06/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=4a85be8477cf4b23971fedf3b06b404cf2231f8fe941630e3e73dc902454b96e
-dist/2025-08-06/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=385625349ab2e79887e2630fc861dcdd039190af36748df27500f7ea45a515f9
-dist/2025-08-06/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=50cec6b681ae63ebcd60ce6cb6d328f49939c3cac1aa6b71ce76a5a3902cb52c
-dist/2025-08-06/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=09a141bf2e457e91abf688c8084654e5e0b932418e351da2c0daf6cf89b77e56
-dist/2025-08-06/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=7aa6d3bd020e903c842725bb3ec9dba1881f2e9cd748953c23c658ef93d49dce
-dist/2025-08-06/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=c00a4b1ad60af59609e3bc61f042f9c4152de26687dcd120da173d61264b88ab
-dist/2025-08-06/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=fcca5576b2f0bdab5bf7dd7ecb6ea956285aa3c129a1ea9facaf517f09f20c2d
-dist/2025-08-06/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=434d9bff2e5693db416701730af1a71767715e98d674cf7273b32f76128ccab1
-dist/2025-08-06/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=af48289fe813a45eb78373d80f01f060ebd2ce6337763d1ee8ea6f5080cb4eb1
-dist/2025-08-06/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=68b2704b80c8f0706dc4bdba4db3b620afecbe086a7d858749d84d56f130979b
-dist/2025-08-06/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=930b287659104dbf4fe759d450a4126b7a0f855fbe8fd7d3ab11aadb18ceccfa
-dist/2025-08-06/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=7580ce2af926de7e07ad2313ae6397a624b10532556f7f9b9cee8ecd5addc697
-dist/2025-08-06/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ed19716bdb95eb04e64299c04725c7a0b92c66121856ab891bb67a797c8b1087
-dist/2025-08-06/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=1d4077c7b42aabe2b80a19f3c96b457901f81667d62a5be9df617543245f0d8c
-dist/2025-08-06/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=e0203ce7cea0c2125d8d39d92c5137b2397115c4d99f42d0b23746d0270c78d2
-dist/2025-08-06/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=0a836d9d2fc5824aeb4afd5eba709c0e3c6d4403ca8815356a0ac8735cbc95dc
-dist/2025-08-06/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=f656cb9adff0aa53f47f15a937556e9b1a9418f33dff39350e48ab8c02da987a
-dist/2025-08-06/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=c44a884292ffeba027d3d029d6d53ccaa2bb85787e825c9cc1dca464046a7855
-dist/2025-08-06/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=6992586e7dc3b95ddaa630cb61f58ec88b5d7c488aed8476be25a92d0fb4a3dd
-dist/2025-08-06/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=6e053aee8964a26385292dc2e9b671995045bb736447059e536b1e7f09c79685
-dist/2025-08-06/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=611d609f23f75a2b7fe304737abaf017fcf4594d9d11cbe014e91a90ee5ab27f
-dist/2025-08-06/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=932f888a1a604358ad40d62bc0ca9a484f47715e8a5306fe77ae610ada4671ce
-dist/2025-08-06/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=4eae3ed539b4ff8b39dae4ea4089081fa49807d31640129eec29b47030e8101e
-dist/2025-08-06/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=13c65d2427c063961c19b20aa4f25bb11b3189084e2f0a798a846b95c630735b
-dist/2025-08-06/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=2f8e8ec9a4c0187174a0d8d3c2addf75e68a2d60920ae100f37efb5e57a45033
-dist/2025-08-06/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=e11b21d9aa403a1202c299390210d11d403501f6f55cc7ec24d6118461545825
-dist/2025-08-06/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=ece7d348df665d6ff6d061e911c6bb4c9d4f161e63e888d3a66f17b533843886
-dist/2025-08-06/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=d87c2370e2346587d71994ba31a0455932760507fcce680ab39322619179c429
-dist/2025-08-06/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=030355ceaa2697d8b2d2de41b56cc4ef50124aa81b2f226cf0d56a1e011e0fa6
-dist/2025-08-06/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=d725272b6b92059afd637a3edfc6dc2b22013bf4e70a0ed1f7c5aad3c6a71fca
-dist/2025-08-06/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=f0c3e7de4e92f696585bd6a85c30fab337548e4393c3ec5b52832f3533acb063
-dist/2025-08-06/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=79f6a3429c2ee29e1350bfce20f7f5ca1e5ec46720194cf3f34977fe446c79cd
-dist/2025-08-06/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=777568cc6df1ce1b96f291027a5024109c189e83e2e2c046a3248e3a1cbedcc6
-dist/2025-08-06/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=2528c1e6256bd9e73174b435802702bbe66eaaa4cff3748d3e5b7580ca7bc789
-dist/2025-08-06/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=2f62d01498b57395e03ddfffc4e0b5cdf78a7fb6f5308440b8eee24637874752
-dist/2025-08-06/rustfmt-nightly-x86_64-apple-darwin.tar.gz=a9b2f612748bc7a88eced4462999c67eeba0ea46f4a73977513c34c09286b0a3
-dist/2025-08-06/rustfmt-nightly-x86_64-apple-darwin.tar.xz=a8137526bc41ab13a624aa5c9895abcc250f38776aeb690a7939baab1093f388
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-solaris.tar.gz=18015624ba6cc1892d944d6f3c82e0b22fc5ff85ac074d25ad80fb4af12f0172
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-solaris.tar.xz=bc0f5d324b4b807b0a378aa0e132a429c57c4773c6d9d30e9215ba835de1a0a5
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=de159bd0f81d54906d8020b3da80ab3319292907c3f0c9c68654f8e6ed900135
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=6dd48c3a64fcc0f2f99e4cc643cf82f1a7efab1921918fd37953c64125982606
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=8ba8c7ce8715fb378758ae8bd6c1538e538c2dfe86771db43b7903f18a384ad3
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=4259f65663aea76e1397c677bc286588cd4b6f8694647c738efc55e5616bc084
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=bfd3e1434e5b816d9d338e6c56203f58b5c1a89499ca03099d4d86b3c665f0d1
-dist/2025-08-06/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=6260a7487d7d3759aea9e6691ac77ee38948a538f8b973459f444f98912753e0
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=c10b36a6ac99d8e1de73c3ae0ca74ef10600baf7a3963f6885282b97f703f992
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=b8de069c788f4a6c195d7a429ed656a45ea2a9a5775138de46d79c1c3591e70e
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=b0f0d9331d213015493e080f8cd06e6ed955693981241acd692a92dd545df66f
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=91ed6b2792622c68a5cc3698650860373305a39162b2b643b1c219cab6debbba
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=b1920a45d2532f41956b2c1112cf8c590243b1417bc48f3922056e1d62a27a1d
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=1825ed54530deb070d6f894cc12ca157be57a37e6d7ccc6007a51674eae42082
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=ac01818b1cc9130b4dcdad9db8137382655d21df9d6e7edc5cd0f84c71bbe787
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=21ee5aeb048e5337b3231b4f3ca8a6bfacc3a1cc23800052093d360ca22b3b78
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=020995d3e24b4e72b0166662fd2e6969f397baa728999bbd09bce76e5381e0b5
-dist/2025-08-06/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=4a09cad2bd24ae6a15c83fb9098f66208219d3ab14c9fd46a3ce7a3c8efe6119
-dist/2025-08-06/rustc-nightly-aarch64-apple-darwin.tar.gz=25e5461350634cbd4b38dce96bc6ba6a9fbdb87caed51f26dfa058105bbccb4a
-dist/2025-08-06/rustc-nightly-aarch64-apple-darwin.tar.xz=e8774ab1e12ba4d3d088dfb0c6a929b3fb6866db035eb10a60b203a6af59f490
-dist/2025-08-06/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=0094366fa4b8f33c7ec5bb75fa5116044c76f3b7bf4a96b5a48b31dbf6f080eb
-dist/2025-08-06/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=6686cbf9182560d9b691ac56b3e89ed76c4fe6340dd036820a1a126e2ff41689
-dist/2025-08-06/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=d3e23b1b5ac10b0cc406eb5397da7fff30aa4e558832379debf4410551ebdc4d
-dist/2025-08-06/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=fd2771191a84469c6b1fcef7e90388f4699ef087e082c9838ca2bb2d1d50b399
-dist/2025-08-06/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=d4848e6a71e9cb6b87e46843f61da911ae81266f5c3aca10f85120d069d304bb
-dist/2025-08-06/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=b1e9c97f2b1c06ebf1dc00cf5fa23191a86e3ef234ebaeeced2bd41b3e59b656
-dist/2025-08-06/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=4d68bc5ecf31127f67d1bb2359e9ca475ea7a0c396da29b00781929f1f00ba6c
-dist/2025-08-06/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=8588747d7ce6c5a9b68ba6805b63449695e60d2e9ea7f3f0ad5f4e5a04d9062c
-dist/2025-08-06/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=4ebb3bd5e06737d2b61f249a674cda32a2a58e871039c37d49c2d6c8d2ecd6d9
-dist/2025-08-06/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=5740de96cfbdcc5261e0df10e9c7ec63e28bd553f9691a8e26e6fe9f76cbbee3
-dist/2025-08-06/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=a7f5f4a9b5c0b6d2cf2f86feac062018e044cfbd05c9cc8243e2ff44d8196745
-dist/2025-08-06/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=a1f54aab1b4a5ebc09d9b57c892072dfd8d5280fe7a0f3dd3f643ffc72992d34
-dist/2025-08-06/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=cac4ed0ff044997a35471f6c291bb165b48cdcf3f0a0a4df24d7c91cbe121362
-dist/2025-08-06/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=47e6083275169ef75dde6daae2bb9ca599ea03ce56d31945e9e0b42d09ebf364
-dist/2025-08-06/rustc-nightly-i686-pc-windows-gnu.tar.gz=95c87a447d33748fbfa1e9136dfb290814a7dfb1a28efc45f14f0c7830ec49bb
-dist/2025-08-06/rustc-nightly-i686-pc-windows-gnu.tar.xz=52929264f954609165aca5d925d6a1f0e41f78647b45edcd8a7c8c3f872c4bd7
-dist/2025-08-06/rustc-nightly-i686-pc-windows-msvc.tar.gz=f8db463c7c5aeb7fda6d0aa2e4d460d42a7fca5ec8b9b4d8a97e4f988c72a1bd
-dist/2025-08-06/rustc-nightly-i686-pc-windows-msvc.tar.xz=b33e23dfc673dda3eaa81d3c2d690e68cbc95bfb09864c8b2307029b0509c4f0
-dist/2025-08-06/rustc-nightly-i686-unknown-linux-gnu.tar.gz=f4f243206778a3997e3ab63170182a6e210cedd47c2a17358146e3e2cb892912
-dist/2025-08-06/rustc-nightly-i686-unknown-linux-gnu.tar.xz=194cda3450befacd2da23bccf836995f09a85e7e9c6d4ba5613cbb3c1768815f
-dist/2025-08-06/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=f189ae4ab931c61eef04b5748b696070b998699315629a3b95d4f0b4cdae9ff9
-dist/2025-08-06/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=23c82bf0d9f5532d94a24cfaeec66fc5f02e1b28c854e5689babd41ebcfc0ad2
-dist/2025-08-06/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=3e76a7201dd24f9d79589445509f0c80e6902864731f71d1da3f5343a75aa5bc
-dist/2025-08-06/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=3a62df3e5497fee4e56bc428db422990c7df924f72dacb6897b3783560a967c8
-dist/2025-08-06/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=cc5c126bb1ad662dc78a3b4b039e6cd32445b45b163886180fda199cbfdae9df
-dist/2025-08-06/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=1c9ecfef304fb901ec6f2cfd4e170d1f02511bb2a84de664718c20c7d154e313
-dist/2025-08-06/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=76b6c1025d9dc045bfdfb5e0ca8e9cde674d0c40bb67f600ecb0e765b9f71f03
-dist/2025-08-06/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=bf08f2bbd2197919acfcdf8db8130882ec8f77cb41371729072e7e94cc54997b
-dist/2025-08-06/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=7e5e5816a18c3b22a5a5cd0814206c3cb53c7fa2ce3d36c9c045e1fac87b0747
-dist/2025-08-06/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=6470b0bbe1a82064de13bd9540acbd2368421e8b000cfd8af05886a48cf11d2c
-dist/2025-08-06/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=1a2cfbf02e55995793bdd9cf3809ace31a3d9900667ec6d5e71c6c63af26f578
-dist/2025-08-06/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=7ea6594b669fa77481ff8ec4e8cf447c11e021a412584e1e60f0baed0976316e
-dist/2025-08-06/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=5cbd5821ad528d90f191a17d019b71ac2beea413b00ceec78aef9433832b2469
-dist/2025-08-06/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=86002592eb275d582ec8656d903ddd2247a0fcfdb2c6d90f337735a574debb9a
-dist/2025-08-06/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=1c420af2bb6af11b2a718ff02d96794e9916a7f538d622b418f39ecd451e1fd6
-dist/2025-08-06/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=1c33f80fbc3284d8499ec03bddb5bd9ebbe7e0da1aac6675d8442a3443440c3c
-dist/2025-08-06/rustc-nightly-sparcv9-sun-solaris.tar.gz=366a9097aaf91fd8b2853b2f94d82b8baf162dae5ef1b514072b4da19fec87a5
-dist/2025-08-06/rustc-nightly-sparcv9-sun-solaris.tar.xz=eca0aaa16e5e7006b19e56330157545d0fb56a5e590c92e041afbc8205c35ab0
-dist/2025-08-06/rustc-nightly-x86_64-apple-darwin.tar.gz=f2665645f498cc57e0b6cb052715afd264b7bb3184be58d50f528562a1610111
-dist/2025-08-06/rustc-nightly-x86_64-apple-darwin.tar.xz=2d5dba8ed862c80035ef742d9a45c1e122228219b4e1da8fd8b920eb589bbe71
-dist/2025-08-06/rustc-nightly-x86_64-pc-solaris.tar.gz=6970602ef52246883c2df83795cca94356a1e978265facab3dd3f838707d31d3
-dist/2025-08-06/rustc-nightly-x86_64-pc-solaris.tar.xz=92e7a314326015586054cdd5044c3123f41972432b2167f0dd551ee9380d66ca
-dist/2025-08-06/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=5405ac07a580ba16b0f95ed0fc56a24318e8aab7abfe04c2ed3c87f9d6f1edcb
-dist/2025-08-06/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=10d189c68491e15b6dd34b7f47bf8c72ccb8ab7260c4d815cb51046fd24ad76c
-dist/2025-08-06/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=812a29f858412b9c256184e8e2b3d65d0c9912d7f4157a9ba640c8231caa5160
-dist/2025-08-06/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=aa22d4547d85669a17c8a475baf533614d8d0547b1e386dc11bde66f215a874c
-dist/2025-08-06/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=5e60c66f60a4358c0f8b2fea5577f71f4c056c7b2d0afefd9289f782004fbc63
-dist/2025-08-06/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=6d975c907e1def685c14fe6e460001af0362824f771585f9b1ccc2cc1ea71fac
-dist/2025-08-06/rustc-nightly-x86_64-unknown-freebsd.tar.gz=465206e95e2c6a7731ca55db9e576f1f78e9d356ba81c6687752793101c80b92
-dist/2025-08-06/rustc-nightly-x86_64-unknown-freebsd.tar.xz=13cd73704262a891ea825201e6583c171f7a920c1be5372b4cccf5cbe3d294fc
-dist/2025-08-06/rustc-nightly-x86_64-unknown-illumos.tar.gz=a7bf182bf19812d41e103a8d89e6c3457c1c9d0ddd800f59fdc3d94df587e3c3
-dist/2025-08-06/rustc-nightly-x86_64-unknown-illumos.tar.xz=43da78e7dca1415ecd756ef13fd08a8358b8deedf406d18801f36e38843a704f
-dist/2025-08-06/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=ef6381475d22aff666429754e25855e97a4dc39e8d508c02a0e353df58afcaba
-dist/2025-08-06/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=238910ad25562d4f7fa6c83d92f9cad5ec3817191907958fa646251c9bcdb690
-dist/2025-08-06/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=df2464c2f2c9233f2009ac73924e95b7dd395c8575874a3391fe2f3dfcfda327
-dist/2025-08-06/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=99c5a9d7f0e7f9e3acde96bfd1d23a11100be81a3651e8267e6e0ffca6bc553d
-dist/2025-08-06/rustc-nightly-x86_64-unknown-netbsd.tar.gz=705dd37d72d99694234af13a561dd9995a0e4c2bfd888aa451b666f49a7083a7
-dist/2025-08-06/rustc-nightly-x86_64-unknown-netbsd.tar.xz=0dc9551d63131336cd97b7bfca984970fc8e5c366b39e04a179673f7859f4c1e
+dist/2025-09-05/rustfmt-nightly-aarch64-apple-darwin.tar.gz=6fd7eece7221e76c2596e0472e7311fdced87e9fab26d2a4673a3242fe779bd3
+dist/2025-09-05/rustfmt-nightly-aarch64-apple-darwin.tar.xz=1a662a55931f58be9ac05841360305f277f8b1e36f99bd0a2ee4d2cc92b7ad14
+dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=d1c3c52cf61522697d726b32ed28d7b8b4cfadf30ec57f242e8c7f9f8e09f692
+dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=2cc7cbbfa06803a2fe422ed3266f6eb519360b403c83f92259cc1b83f5ddca45
+dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=61f525d050d1ff4a29cc7240912d84c9c091f25195b58411af9ef176175a3200
+dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=504b8ace2ab7ac13be143d95ed74d94940e8706ef9f53b7778da215840337e20
+dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=ff48bd98d109310638822f5813042583900e2b70edd45fccd871c7c03dd1c2e6
+dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=b3de2bba7858e76cdafd326f3072e4c5b534ca9b679ea62caeffb07722e9a3c9
+dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=8ca4caedc50f09995dad7bc6e001cc863c524e28c45c186022ded589f3728709
+dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=8f2cfb052f9697052d89bb729d17d74583af3fa0be98f18a3c44ea518a8f4855
+dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=b12ac2a38b379bf0de4a92f29ca40e1955c45273e798edd1a72bd40253de70f1
+dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=87fb7185aa46f3810e09479dc8fafb66d13b41f4f40e9c4e866ea77fa47b1bb6
+dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=be1e8377f3d10f4f8a07ae06ab9f649f9d2fc9cfc395abaa5f0ad10a95c4fe7a
+dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=60646799fdacdafec9e0ed81357b5db70f85bb1241fe775e71b8ad3feb686116
+dist/2025-09-05/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=ed8cade9b846efb5ac121aa70ac188fbd2e61fa9402fe68c80b2cbd3ee32ccbd
+dist/2025-09-05/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=0d0bfbd9cd4123e0404fe476a6f16eec6e435ce28d328dc0dd0aad257b295d64
+dist/2025-09-05/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=bd411db34707c36d5b60f14bba776b0b89b69d4266007a3b591c467a17ef053c
+dist/2025-09-05/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=f0f2a6a81177ae6d06ff9b8f4a5bdf3bc8b26710aaf0f09258b32f7f710722c0
+dist/2025-09-05/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=b49130da444e01fe4ef997b649aada8978b8dcca60dd38cf9e7400a7c7569e1b
+dist/2025-09-05/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=0195cdddc74cba2bf17eaa1d53edb1a2bc0e34cdf13c7b25a34ad9729a2635b8
+dist/2025-09-05/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=1141897495ddca10fd6d9476a624b6a340fc2bfc619148e183bcf355a0078b18
+dist/2025-09-05/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=81b31bc8b3d431120005c3c8eeff3ed194dd18e56220c175c3250855cbdcddbe
+dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=10a27070239e7dfcf701669c8d93ecb2d310b9fde768639a2bf5be62cd13528d
+dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=0ac4a529f4f62a94d5ae4cc8a4a52f0e7d57296ac0884258dcc5478e6b0b1785
+dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=9d0ed6778fc4f0601be1e317438cf95c414fcab6d3207c635babb4f3a6faf2b0
+dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=e40b607faf2f37c9d654cc0b60c47ea155893a3b62236cd66728f68665becb18
+dist/2025-09-05/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=46c029ebbfa35972b0b9e366d17c41ff8e278e01ce12634d5e3146cbf6d1a32e
+dist/2025-09-05/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=8d1462fd09b04a94bfb1c1841c522430b644961995bf0e19e7c8fa150628e7c7
+dist/2025-09-05/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=5827684ccb4d38956e77858ddeadeaff2d92905c67093207bed0f38202268151
+dist/2025-09-05/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=975c7d7beb5b66caed7d507aaec092fdf33de2308f4dc7de46fe74e5e15b5352
+dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=8829677ab0f898c98badf22dad61094cf53c6d599b2cc76142d3d792a44f3770
+dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3d961bead4010f8a488a065ac8a4153e3c747dfcd7d5f7eeba1cad00767a7ac5
+dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=0138c30ebe74e8ee838d9eef31c7882812bb52d2304f2de7c23c47dedd6a5032
+dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=bdb4b7b3c89a30c79f51b5fa33a2a29fc8313f8193bc43ee611e8ce7d80382d2
+dist/2025-09-05/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=8e440dd400bf3eb4a144318459e111069a64bb309a5a51eeb0f0383dc48ee55f
+dist/2025-09-05/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=f623e1d7d38d94965d7653fdf4a272630b2b6dec81662fbbe5d2573f2f3f3b8f
+dist/2025-09-05/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=f46a8278352d5a981c6746b876fe19df3093090a866d20d24cd5cb081136b1c0
+dist/2025-09-05/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=fdf8b44c6f110a33ad7f969e651ad396c880a85545aadfee8a24ca3cbed35974
+dist/2025-09-05/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=59d778dea354867d64c809b40443ca0762c685dd0e5361971daab04aa7c5a5ad
+dist/2025-09-05/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=18628b2888d77281fc9b2ac5636ce4ec444ab0e47bbe0e8a08238f90040c20a3
+dist/2025-09-05/rustfmt-nightly-x86_64-apple-darwin.tar.gz=169d9f2ee4a0c726040f4940370d1162502aa6568a0a442c92cad3fbc7bd95c2
+dist/2025-09-05/rustfmt-nightly-x86_64-apple-darwin.tar.xz=7f955cfa1ab07819f31cd904b0a79c67cae70090aabc7dafffdc1f3f67463248
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-solaris.tar.gz=d2cc32d6be1d0f1a8654400f0418d16e789b62db3fbc0cca0d0d492615bcf6e2
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-solaris.tar.xz=3dbc29c923a6a2809a8ef561d2ad375211b09dcb107bceabbf510ab0d7b471f0
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=d9b4ca2abf1062e888b31f31f517ccc6b451bd2bfdae915ec3984bc88a8be91a
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=00c6d92b6e82ae58e682e72c974f2dcc865820567ba44ed008e4759dfdbdca87
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=e75424d0aece8d548b2c9d896291288615d08ff2a37f1c4844a70839c612e633
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=cce9578d9b35bd8192a26e2dc7d7f7e7d5b9f08c7d73b3f4dde08208b448b063
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=ac4282e06b0972033f974c63d2c6cbf194d4e66a1c811f443d3fa0b886868825
+dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=a2465b31855861d0e0eea072bb366480acf2bafdd7fdfdab79c809d8bbf8d8e4
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=30c22a97066a5711f207c1919a1d74a328540da0d9d6f85a0cc044174049c927
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=40987da0b665940f9c406cfbb4889dc101d73846730b0bdfa1382d051297ad08
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=443ba10092122fbba9854abb4aa9d2e71d8e5e65b99fae6dd572909bf50f28c5
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=10285942b9140efc9897965cb3a4204145e774bd1b0c2690d45d8b04498fb917
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=b09af4fe367df416bce622654d9e3dfb610c564f5e6d14b200d949340595673c
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=1f9a585a017cee5a05190377cab105603f039fbefd9b4934278dc555dfca91b0
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=24f911745fcc9f120e44acccb98f54dc6406e492915410aae17efdd00e2752c3
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=48eb58ba1d58701dbff341e19fb6d446ed937cc410207b35297babafa29dd889
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=c2d1cfdcd8a08bde3f9a635eaf2d6d2fbd82e4cabbbd459e3c47e64bf1581f11
+dist/2025-09-05/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=ed1775b4fd3d7d1203f8749f70328ea4ade802fa0a76c4d7ab3e2d63ca1535af
+dist/2025-09-05/rustc-nightly-aarch64-apple-darwin.tar.gz=4b64c4148e5cdd6585a4200125cc394c6a998da3686ef758f37742ec2d33d573
+dist/2025-09-05/rustc-nightly-aarch64-apple-darwin.tar.xz=fd45182f9db059bdc17f2c465dbaae22589eb8e8d2d88776437a34ddca3b7153
+dist/2025-09-05/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=c14f2d7f391492d150f2f2f91af413266649cbdbdb042fc8b660b3cb141b80c7
+dist/2025-09-05/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=d72ea1c571fe2376ef05cfd15fb3207ee2d27c3c851f3391dfbb082c06a5bdd0
+dist/2025-09-05/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=3a485d8fd8d58fdfbc1216e51414aa4d90f0c7285a99abea0fa5935d2337251b
+dist/2025-09-05/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=7317060a29eecd2e28d47f0ff8780150059756b07e2bc9137c3877be8af593b7
+dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=58a53ae147de1beb0a53629898bf7c51097351271be3713a2e2344b86a4080a4
+dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=f79d2730843dbea9e9588fd1c1b0d854441969d8f93f76021f06af2efe22b845
+dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=eddf23e28b8067021e80883faf2eb1d6d3005a6e8419a1232b84236bea286f78
+dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=4f0af1a66050f5e2d9d48b696349b9ccd420bdcfdb88b251a6655cc22a11949b
+dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=fd2f0446e3c993d746e8a5f72ccebd8b0a49172316ac1d1c58bad10596becbf3
+dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=0b06e7ba47621819b4e59e048e5d336b3d6978e906c7363f06bbc804e49f1046
+dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=97d7c34b53628f28e6636fae738a18d0f1f4c60a9febddfb7145e6b91fcf3fdc
+dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=323025215bf851024a7eb6566ad7dc5719832d81e8d46e70adaece98adc5644b
+dist/2025-09-05/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=3017e03222d030448ffe2805624143540197bd6d3b3e93f9f73469ace25ae4be
+dist/2025-09-05/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=4f6e86b185fb54f7a0b7d09a0faae7daac722351354f6abebd388efb3037dfa0
+dist/2025-09-05/rustc-nightly-i686-pc-windows-gnu.tar.gz=292c3770b96cde97072d70c58234488f955ed5582b7c3044c6de66891e73d639
+dist/2025-09-05/rustc-nightly-i686-pc-windows-gnu.tar.xz=6855d3fd9040fb4da554fd732eaf8a1c723921c35bb8a8efb31c78af69b2e4ec
+dist/2025-09-05/rustc-nightly-i686-pc-windows-msvc.tar.gz=64a86a2971ed9934bbb6aaa0afc2a7f747da463afb55b51a7c5fdbdaa294e437
+dist/2025-09-05/rustc-nightly-i686-pc-windows-msvc.tar.xz=c98f1fc3e077b8c8eb3e526c416a6551c08c62e58be57b4a4c7d59670bc435f9
+dist/2025-09-05/rustc-nightly-i686-unknown-linux-gnu.tar.gz=5481c97d788899f896473380dde0877808489bc4a0ed6d98265558631fa67a57
+dist/2025-09-05/rustc-nightly-i686-unknown-linux-gnu.tar.xz=afadaae945c0b9a8b50dbdee28791e0c03c880cb22d3c20996eeb7fab94df0bf
+dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=18b276a2464b6c5a817d72384f25442c7619cac05b2d8d0af212c0dad96ccfc6
+dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=b74323cd2dbee966eebe8e63e24fae026ecd900a025e9167cca0341e50333cc3
+dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=916dc5144107d9173479b320b55b0a95d2d42156c69fbdb0f21377d825fe0892
+dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=3a83da72aa4a6553ecd957af35a05274528dc79f87d24d8470c20b8b4478b05b
+dist/2025-09-05/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=59e031b6b79a1f11406c0640e1a357f2941967ea8c034a94148d60928038e58e
+dist/2025-09-05/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=53f0e33cf2651d5dc8931ec5af8f04994188d8f9a10a5c61bd72cc822df34501
+dist/2025-09-05/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=0eec56e3b725d918cb21e494a803b2e38eb6d744f64f1a82481a4c704eb7c1f0
+dist/2025-09-05/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=5efc97abb235f349c6cc952b4a1e4dae7d56d70b0f8b8da2a1060b85f9b734fd
+dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=cb45bbcdf8841b1ac184a0aacc909f153c830e8051260e09ca4e32c1f048e2fb
+dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=1c9ddddb90d45612e4fd190fb71e527b523df13146343dde200580fb2b638794
+dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=3a9bdd4d14e8f121d3051944ee83a901b5ca4c0921f2d01e34596fb7450b49e3
+dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=732b9abb8a80191884fe1ff1d4d923cc1b74c21b81e6327bc5979ae526337400
+dist/2025-09-05/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=1826e74200fe286478e1659ab88ea86b43efa7b023074d00dbc814d80bebc883
+dist/2025-09-05/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=c30b52d0f474fd6193bb1b3e147fb79fa8cc31e5db38444f023d84d1c2d93d12
+dist/2025-09-05/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=c330067621ed25d8383f27e494346eca4d7d4866e48f331f2ec897ff1c386e56
+dist/2025-09-05/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=cb4097ea582a83a94cab80ff2f36b6f7141c140d75c30b1d261a1ddd4ea45bd4
+dist/2025-09-05/rustc-nightly-sparcv9-sun-solaris.tar.gz=0af19e764f10333017a3ab66020b82c7185ad648d1230b68f10977e0affb937f
+dist/2025-09-05/rustc-nightly-sparcv9-sun-solaris.tar.xz=a22cfb55cdd122dd99bf3566eabd781bb2ecded90c71a41fd33b1e0588bcc39c
+dist/2025-09-05/rustc-nightly-x86_64-apple-darwin.tar.gz=163a07b91e36e85c6c41368598793667414cdc6cadc980866811234539f3aec3
+dist/2025-09-05/rustc-nightly-x86_64-apple-darwin.tar.xz=76711800685b39b3b75945395682062c40efe3195f9979784bf318837e21768a
+dist/2025-09-05/rustc-nightly-x86_64-pc-solaris.tar.gz=69142a6c04703c3c8309c6fdf66b25831bf9efa3ee70cc93da4b5b75f901b29a
+dist/2025-09-05/rustc-nightly-x86_64-pc-solaris.tar.xz=7e535f4aa136284e4bdfd4d56891caac6844dab91e1b711fa3914a5974dfcb60
+dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=ff0ea563126ff28df297258001d9fac4dbd85788b5d27a0f5d6be75306f21139
+dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=6b66adcaa9a5332979591464242423897f59276e9e2cbeb9ab038a72e72c3a5c
+dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=64cac5e377bc115a8f8176719575903e695337941db43cfb35546d65c0723130
+dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=11e2765e4b3e2296ea05ecf735cf7b5f7beb08d76d12449cfae67f88bab02819
+dist/2025-09-05/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=c7d15ae7cd5af774ae70e63fec3ba8723b85fa4c4640917b3960907eedb30b39
+dist/2025-09-05/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=55036567af270cdac046fb4306e515787ca6ef5073617311fac79fb87ffe9366
+dist/2025-09-05/rustc-nightly-x86_64-unknown-freebsd.tar.gz=2d24470d2bb4c4d2605c15f1b2654cc45805384babb73b1960e8aea0b8cc227d
+dist/2025-09-05/rustc-nightly-x86_64-unknown-freebsd.tar.xz=fa41782cb2e22aba30d1619db1f478c0305944ceb4de1d1001f221c5c68c104e
+dist/2025-09-05/rustc-nightly-x86_64-unknown-illumos.tar.gz=d0f9785f76c59f3a67a499cfff4a5639f3ae05cbc76750b867faaa60b7d67f78
+dist/2025-09-05/rustc-nightly-x86_64-unknown-illumos.tar.xz=925e473c6e31d8811879a805358cfd2e5ab8f4de836c270d02dc8403771bed3a
+dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=ebac845114b89dfe7d0efc0cfe8820902faad617ed21eb2a701d73cf7b544a85
+dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=2512a5462e3f46c95ed4aba4228282a357b3e0694e9db117a857196448fe7bcc
+dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b4a5d364b84464e9a92140fff50349d4942b8d970b64150a4bc6d720cc6c4a4e
+dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=6c57c2edc305737530f8551d789ee79ff952f42a0d52d6f8d7d7f1ea2027cfca
+dist/2025-09-05/rustc-nightly-x86_64-unknown-netbsd.tar.gz=f3192ded327875d5a27fb50c690e3fce36669e8f71c47de304dc21edad573ff9
+dist/2025-09-05/rustc-nightly-x86_64-unknown-netbsd.tar.xz=11359e4731866f6a788e5699867e45befdf1ad49ef35c0aba22af76d3f327cc3
diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml
index b7f3625da91..79097f2c189 100644
--- a/src/tools/bump-stage0/Cargo.toml
+++ b/src/tools/bump-stage0/Cargo.toml
@@ -11,4 +11,4 @@ build_helper = { path = "../../build_helper" }
 curl = "0.4.38"
 indexmap = { version = "2.0.0", features = ["serde"] }
 serde = { version = "1.0.125", features = ["derive"] }
-toml = "0.7"
+toml = "0.8.23"
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index 680437cce4f..faed748785f 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -185,7 +185,11 @@ fn fetch_manifest(
         format!("{}/dist/channel-rust-{}.toml", config.dist_server, channel)
     };
 
-    Ok(toml::from_slice(&http_get(&url)?)?)
+    // FIXME: on newer `toml` (>= `0.9.*`), use `toml::from_slice`. For now, we use the most recent
+    // `toml` available in-tree which is `0.8.*`, so we have to do an additional dance here.
+    let response = http_get(&url)?;
+    let response = String::from_utf8(response)?;
+    Ok(toml::from_str(&response)?)
 }
 
 fn http_get(url: &str) -> Result<Vec<u8>, Error> {
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject a6c58d43051d01d83f55a3e61ef5f5b2b0dd6bd
+Subproject 761c4658d0079d607e6d33cf0c060e61a617cad
diff --git a/src/tools/clippy/.cargo/config.toml b/src/tools/clippy/.cargo/config.toml
index d9c635df5dc..a09bf95e87b 100644
--- a/src/tools/clippy/.cargo/config.toml
+++ b/src/tools/clippy/.cargo/config.toml
@@ -23,3 +23,10 @@ split-debuginfo = "unpacked"
 rustflags = ["--remap-path-prefix", "=clippy_dev"]
 [profile.dev.package.lintcheck]
 rustflags = ["--remap-path-prefix", "=lintcheck"]
+
+# quine-mc_cluskey makes up a significant part of the runtime in dogfood
+# due to the number of conditions in the clippy_lints crate
+# and enabling optimizations for that specific dependency helps a bit
+# without increasing total build times.
+[profile.dev.package.quine-mc_cluskey]
+opt-level = 3
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index bc60b1c57f7..eb2a76a8183 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -30,6 +30,8 @@ Current stable, released 2025-08-07
 * Removed superseded lints: `transmute_float_to_int`, `transmute_int_to_char`,
   `transmute_int_to_float`, `transmute_num_to_bytes` (now in rustc)
   [#14703](https://github.com/rust-lang/rust-clippy/pull/14703)
+* Move [`uninlined_format_args`] to `pedantic` (from `style`, now allow-by-default)
+  [#15287](https://github.com/rust-lang/rust-clippy/pull/15287)
 
 ### Enhancements
 
@@ -74,6 +76,9 @@ Current stable, released 2025-08-07
   [#14719](https://github.com/rust-lang/rust-clippy/pull/14719)
 * [`unnecessary_to_owned`] fixed FP when map key is a reference
   [#14834](https://github.com/rust-lang/rust-clippy/pull/14834)
+* [`swap_with_temporary`]: fix false positive leading to different semantics
+  being suggested, and use the right number of dereferences in suggestion
+  [#15172](https://github.com/rust-lang/rust-clippy/pull/15172)
 
 ### ICE Fixes
 
@@ -6707,6 +6712,7 @@ Released 2018-09-13
 [`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers
 [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items
 [`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold
+[`const-literal-digits-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#const-literal-digits-threshold
 [`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros
 [`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods
 [`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 05590ff7b1c..c2d080cd96a 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -485,6 +485,16 @@ The maximum cognitive complexity a function can have
 * [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity)
 
 
+## `const-literal-digits-threshold`
+The minimum digits a const float literal must have to supress the `excessive_precicion` lint
+
+**Default Value:** `30`
+
+---
+**Affected lints:**
+* [`excessive_precision`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision)
+
+
 ## `disallowed-macros`
 The list of disallowed macros, written as fully qualified paths.
 
@@ -555,7 +565,7 @@ default configuration of Clippy. By default, any configuration will replace the
 * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
 * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
 
-**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
 
 ---
 **Affected lints:**
@@ -873,7 +883,6 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow)
 * [`non_std_lazy_statics`](https://rust-lang.github.io/rust-clippy/master/index.html#non_std_lazy_statics)
 * [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref)
-* [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or)
 * [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr)
 * [`question_mark`](https://rust-lang.github.io/rust-clippy/master/index.html#question_mark)
 * [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names)
@@ -881,7 +890,6 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`repeat_vec_with_capacity`](https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity)
 * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push)
 * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current)
-* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind)
 * [`to_digit_is_some`](https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some)
 * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref)
 * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions)
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index 77573105d86..d9bcfd17606 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -6,12 +6,12 @@ lint-commented-code = true
 
 [[disallowed-methods]]
 path = "rustc_lint::context::LintContext::lint"
-reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead"
 
 [[disallowed-methods]]
 path = "rustc_lint::context::LintContext::span_lint"
-reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead"
 
 [[disallowed-methods]]
 path = "rustc_middle::ty::context::TyCtxt::node_span_lint"
-reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead"
+reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead"
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 2ad3f2efcdd..2f28f6175ad 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -33,6 +33,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "GPLv2", "GPLv3",
     "GitHub", "GitLab",
     "IPv4", "IPv6",
+    "InfiniBand", "RoCE",
     "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript",
     "PowerPC", "WebAssembly",
     "NaN", "NaNs",
@@ -569,6 +570,9 @@ define_Conf! {
     /// The maximum cognitive complexity a function can have
     #[lints(cognitive_complexity)]
     cognitive_complexity_threshold: u64 = 25,
+    /// The minimum digits a const float literal must have to supress the `excessive_precicion` lint
+    #[lints(excessive_precision)]
+    const_literal_digits_threshold: usize = 30,
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
     ///
     /// Use the Cognitive Complexity lint instead.
@@ -775,7 +779,6 @@ define_Conf! {
         needless_borrow,
         non_std_lazy_statics,
         option_as_ref_deref,
-        option_map_unwrap_or,
         ptr_as_ptr,
         question_mark,
         redundant_field_names,
@@ -783,7 +786,6 @@ define_Conf! {
         repeat_vec_with_capacity,
         same_item_push,
         seek_from_current,
-        seek_rewind,
         to_digit_is_some,
         transmute_ptr_to_ref,
         tuple_array_conversions,
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index b9e6de79cc0..70184ee2ca5 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -27,6 +27,10 @@ url = "2.2"
 [dev-dependencies]
 walkdir = "2.3"
 
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = ['cfg(bootstrap)']
+
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
 rustc_private = true
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 6f2a6a36a38..08253b0c499 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -3,10 +3,10 @@ use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_no
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
 use clippy_utils::usage::local_used_after_expr;
-use clippy_utils::{is_expr_final_block_expr, path_res, sym};
+use clippy_utils::{path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
@@ -77,17 +77,20 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                 _ => 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,
-                );
+                let recv = snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0;
+
+                // `assert!` doesn't return anything, but `Result::unwrap(_err)` does, so we might need to add a
+                // semicolon to the suggestion to avoid leaking the type
+                let sugg = match cx.tcx.parent_hir_node(e.hir_id) {
+                    // trailing expr of a block
+                    Node::Block(..) => format!("{recv}.{replacement}();"),
+                    // already has a trailing semicolon
+                    Node::Stmt(..) => format!("{recv}.{replacement}()"),
+                    // this is the last-resort option, because it's rather verbose
+                    _ => format!("{{ {recv}.{replacement}(); }}"),
+                };
+                diag.span_suggestion(macro_call.span, "replace with", sugg, app);
             });
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index 013819b0da8..1a10db291cd 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -1,8 +1,12 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::source::snippet;
+use clippy_utils::is_expr_async_block;
+use clippy_utils::source::walk_span_to_context;
+use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
-use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath};
+use rustc_hir::{
+    Block, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 
@@ -87,31 +91,37 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
         let expr_ty = typeck_results.expr_ty(body_expr);
 
         if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
-            let return_expr_span = match &body_expr.kind {
-                // XXXkhuey there has to be a better way.
-                ExprKind::Block(block, _) => block.expr.map(|e| e.span),
-                ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
-                _ => None,
+            let (return_expr, return_expr_span) = match &body_expr.kind {
+                ExprKind::Block(Block { expr: Some(e), .. }, _) => (*e, e.span),
+                ExprKind::Path(QPath::Resolved(_, path)) => (body_expr, path.span),
+                _ => return,
             };
-            if let Some(return_expr_span) = return_expr_span {
-                span_lint_hir_and_then(
-                    cx,
-                    ASYNC_YIELDS_ASYNC,
-                    body_expr.hir_id,
-                    return_expr_span,
-                    "an async construct yields a type which is itself awaitable",
-                    |db| {
-                        db.span_label(body_expr.span, "outer async construct");
-                        db.span_label(return_expr_span, "awaitable value not awaited");
-                        db.span_suggestion(
-                            return_expr_span,
-                            "consider awaiting this value",
-                            format!("{}.await", snippet(cx, return_expr_span, "..")),
-                            Applicability::MaybeIncorrect,
-                        );
-                    },
-                );
+
+            let return_expr_span = walk_span_to_context(return_expr_span, expr.span.ctxt()).unwrap_or(return_expr_span);
+            let mut applicability = Applicability::MaybeIncorrect;
+            let mut return_expr_snip =
+                Sugg::hir_with_context(cx, return_expr, expr.span.ctxt(), "..", &mut applicability);
+            if !is_expr_async_block(return_expr) {
+                return_expr_snip = return_expr_snip.maybe_paren();
             }
+
+            span_lint_hir_and_then(
+                cx,
+                ASYNC_YIELDS_ASYNC,
+                body_expr.hir_id,
+                return_expr_span,
+                "an async construct yields a type which is itself awaitable",
+                |db| {
+                    db.span_label(body_expr.span, "outer async construct");
+                    db.span_label(return_expr_span, "awaitable value not awaited");
+                    db.span_suggestion(
+                        return_expr_span,
+                        "consider awaiting this value",
+                        format!("{return_expr_snip}.await"),
+                        applicability,
+                    );
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/bool_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_comparison.rs
new file mode 100644
index 00000000000..722095909a6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/bool_comparison.rs
@@ -0,0 +1,179 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{is_expn_of, peel_blocks, sym};
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+use rustc_span::source_map::Spanned;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for expressions of the form `x == true`,
+    /// `x != true` and order comparisons such as `x < true` (or vice versa) and
+    /// suggest using the variable directly.
+    ///
+    /// ### Why is this bad?
+    /// Unnecessary code.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// if x == true {}
+    /// if y == false {}
+    /// ```
+    /// use `x` directly:
+    /// ```rust,ignore
+    /// if x {}
+    /// if !y {}
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub BOOL_COMPARISON,
+    complexity,
+    "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
+}
+
+declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]);
+
+impl<'tcx> LateLintPass<'tcx> for BoolComparison {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if e.span.from_expansion() {
+            return;
+        }
+
+        if let ExprKind::Binary(Spanned { node, .. }, left_side, right_side) = e.kind
+            && is_expn_of(left_side.span, sym::cfg).is_none()
+            && is_expn_of(right_side.span, sym::cfg).is_none()
+            && cx.typeck_results().expr_ty(left_side).is_bool()
+            && cx.typeck_results().expr_ty(right_side).is_bool()
+        {
+            let ignore_case = None::<(fn(_) -> _, &str)>;
+            let ignore_no_literal = None::<(fn(_, _) -> _, &str)>;
+            match node {
+                BinOpKind::Eq => {
+                    let true_case = Some((|h| h, "equality checks against true are unnecessary"));
+                    let false_case = Some((
+                        |h: Sugg<'tcx>| !h,
+                        "equality checks against false can be replaced by a negation",
+                    ));
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
+                },
+                BinOpKind::Ne => {
+                    let true_case = Some((
+                        |h: Sugg<'tcx>| !h,
+                        "inequality checks against true can be replaced by a negation",
+                    ));
+                    let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
+                },
+                BinOpKind::Lt => check_comparison(
+                    cx,
+                    e,
+                    ignore_case,
+                    Some((|h| h, "greater than checks against false are unnecessary")),
+                    Some((
+                        |h: Sugg<'tcx>| !h,
+                        "less than comparison against true can be replaced by a negation",
+                    )),
+                    ignore_case,
+                    Some((
+                        |l: Sugg<'tcx>, r: Sugg<'tcx>| (!l).bit_and(&r),
+                        "order comparisons between booleans can be simplified",
+                    )),
+                ),
+                BinOpKind::Gt => check_comparison(
+                    cx,
+                    e,
+                    Some((
+                        |h: Sugg<'tcx>| !h,
+                        "less than comparison against true can be replaced by a negation",
+                    )),
+                    ignore_case,
+                    ignore_case,
+                    Some((|h| h, "greater than checks against false are unnecessary")),
+                    Some((
+                        |l: Sugg<'tcx>, r: Sugg<'tcx>| l.bit_and(&(!r)),
+                        "order comparisons between booleans can be simplified",
+                    )),
+                ),
+                _ => (),
+            }
+        }
+    }
+}
+
+fn check_comparison<'a, 'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>,
+) {
+    if let ExprKind::Binary(_, left_side, right_side) = e.kind {
+        let mut applicability = Applicability::MachineApplicable;
+        // Eliminate parentheses in `e` by using the lo pos of lhs and hi pos of rhs,
+        // calling `source_callsite` make sure macros are handled correctly, see issue #9907
+        let binop_span = left_side.span.source_callsite().to(right_side.span.source_callsite());
+
+        match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
+            (Some(true), None) => left_true.map_or((), |(h, m)| {
+                suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
+            }),
+            (None, Some(true)) => right_true.map_or((), |(h, m)| {
+                suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
+            }),
+            (Some(false), None) => left_false.map_or((), |(h, m)| {
+                suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
+            }),
+            (None, Some(false)) => right_false.map_or((), |(h, m)| {
+                suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
+            }),
+            (None, None) => no_literal.map_or((), |(h, m)| {
+                let left_side = Sugg::hir_with_context(cx, left_side, binop_span.ctxt(), "..", &mut applicability);
+                let right_side = Sugg::hir_with_context(cx, right_side, binop_span.ctxt(), "..", &mut applicability);
+                span_lint_and_sugg(
+                    cx,
+                    BOOL_COMPARISON,
+                    binop_span,
+                    m,
+                    "try",
+                    h(left_side, right_side).into_string(),
+                    applicability,
+                );
+            }),
+            _ => (),
+        }
+    }
+}
+
+fn suggest_bool_comparison<'a, 'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    expr: &Expr<'_>,
+    mut app: Applicability,
+    message: &'static str,
+    conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
+) {
+    let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app);
+    span_lint_and_sugg(
+        cx,
+        BOOL_COMPARISON,
+        span,
+        message,
+        "try",
+        conv_hint(hint).into_string(),
+        app,
+    );
+}
+
+fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
+    if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind
+        && let LitKind::Bool(value) = lit_ptr.node
+    {
+        return Some(value);
+    }
+    None
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index a1543cabd2f..d78da9396fa 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -8,17 +8,12 @@ use rustc_middle::ty::{self, Ty};
 
 use super::CAST_PTR_ALIGNMENT;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
-    if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
-        if is_hir_ty_cfg_dependant(cx, cast_to) {
-            return;
-        }
-        let (cast_from, cast_to) = (
-            cx.typeck_results().expr_ty(cast_expr),
-            cx.typeck_results().expr_ty(expr),
-        );
-        lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
-    } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) {
+    lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
+}
+
+pub(super) fn check_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind
         && method_path.ident.name == sym::cast
         && let Some(generic_args) = method_path.args
         && let [GenericArg::Type(cast_to)] = generic_args.args
@@ -74,14 +69,13 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => {
             if let ExprKind::Path(path) = &func.kind
                 && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
+                && let Some(name) = cx.tcx.get_diagnostic_name(def_id)
                 && matches!(
-                    cx.tcx.get_diagnostic_name(def_id),
-                    Some(
-                        sym::ptr_write_unaligned
-                            | sym::ptr_read_unaligned
-                            | sym::intrinsics_unaligned_volatile_load
-                            | sym::intrinsics_unaligned_volatile_store
-                    )
+                    name,
+                    sym::ptr_write_unaligned
+                        | sym::ptr_read_unaligned
+                        | sym::intrinsics_unaligned_volatile_load
+                        | sym::intrinsics_unaligned_volatile_store
                 )
             {
                 true
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
index 46b0c88d3fe..bce7b4c69cc 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -1,10 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::{get_parent_expr, is_no_std_crate};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::sym;
 
@@ -42,13 +44,52 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         let mut applicability = Applicability::MachineApplicable;
         let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0;
         let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0;
+        let krate = if is_no_std_crate(cx) { "core" } else { "std" };
         span_lint_and_sugg(
             cx,
             CAST_SLICE_FROM_RAW_PARTS,
             span,
             format!("casting the result of `{func}` to {cast_to}"),
             "replace with",
-            format!("core::ptr::slice_{func}({ptr}, {len})"),
+            format!("{krate}::ptr::slice_{func}({ptr}, {len})"),
+            applicability,
+        );
+    }
+}
+
+/// Checks for implicit cast from slice reference to raw slice pointer.
+pub(super) fn check_implicit_cast(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    if let ExprKind::Call(fun, [ptr_arg, len_arg]) = expr.peel_blocks().kind
+        && let ExprKind::Path(ref qpath) = fun.kind
+        && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
+        && let Some(rpk) = raw_parts_kind(cx, fun_def_id)
+        && !matches!(get_parent_expr(cx, expr).map(|e| e.kind), Some(ExprKind::Cast(..)))
+        && let [deref, borrow] = cx.typeck_results().expr_adjustments(expr)
+        && matches!(deref.kind, Adjust::Deref(..))
+        && let Adjustment {
+            kind: Adjust::Borrow(AutoBorrow::RawPtr(..)),
+            target,
+        } = borrow
+        && let ty::RawPtr(pointee_ty, _) = target.kind()
+        && pointee_ty.is_slice()
+        && !expr.span.from_expansion()
+    {
+        let func = match rpk {
+            RawPartsKind::Immutable => "from_raw_parts",
+            RawPartsKind::Mutable => "from_raw_parts_mut",
+        };
+        let mut applicability = Applicability::MachineApplicable;
+        let ctxt = expr.span.ctxt();
+        let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0;
+        let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0;
+        let krate = if is_no_std_crate(cx) { "core" } else { "std" };
+        span_lint_and_sugg(
+            cx,
+            CAST_SLICE_FROM_RAW_PARTS,
+            expr.span,
+            format!("implicitly casting the result of `{func}` to `{target}`"),
+            "replace_with",
+            format!("{krate}::ptr::slice_{func}({ptr}, {len})"),
             applicability,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index e25df9dd249..d2e62ee56e4 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -873,7 +873,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             }
             char_lit_as_u8::check(cx, expr, cast_from_expr, cast_to);
             cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, self.msrv);
+            cast_ptr_alignment::check(cx, expr, cast_from, cast_to);
             ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
+            ptr_as_ptr::check(cx, expr, cast_from_expr, cast_from, cast_to_hir, cast_to, self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
             fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to);
             confusing_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
@@ -911,8 +913,10 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
         if self.msrv.meets(cx, msrvs::RAW_REF_OP) {
             borrow_as_ptr::check_implicit_cast(cx, expr);
         }
-        cast_ptr_alignment::check(cx, expr);
-        ptr_as_ptr::check(cx, expr, self.msrv);
+        if self.msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) {
+            cast_slice_from_raw_parts::check_implicit_cast(cx, expr);
+        }
+        cast_ptr_alignment::check_cast_method(cx, expr);
         cast_slice_different_sizes::check(cx, expr, self.msrv);
         ptr_cast_constness::check_null_ptr_cast_method(cx, expr);
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 89075409098..d012380cb76 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -4,9 +4,9 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind};
+use rustc_hir::{self as hir, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, sym};
 
 use super::PTR_AS_PTR;
@@ -26,13 +26,18 @@ impl OmitFollowedCastReason<'_> {
     }
 }
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) {
-    if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind
-        && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr))
-        && let ty::RawPtr(_, from_mutbl) = cast_from.kind()
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &Expr<'tcx>,
+    cast_from_expr: &Expr<'_>,
+    cast_from: Ty<'_>,
+    cast_to_hir: &hir::Ty<'_>,
+    cast_to: Ty<'tcx>,
+    msrv: Msrv,
+) {
+    if let ty::RawPtr(_, from_mutbl) = cast_from.kind()
         && let ty::RawPtr(to_pointee_ty, to_mutbl) = cast_to.kind()
-        && matches!((from_mutbl, to_mutbl),
-            (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut))
+        && from_mutbl == to_mutbl
         // The `U` in `pointer::cast` have to be `Sized`
         // as explained here: https://github.com/rust-lang/rust/issues/60602.
         && to_pointee_ty.is_sized(cx.tcx, cx.typing_env())
@@ -40,7 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv)
         && !is_from_proc_macro(cx, expr)
     {
         let mut app = Applicability::MachineApplicable;
-        let turbofish = match &cast_to_hir_ty.kind {
+        let turbofish = match &cast_to_hir.kind {
             TyKind::Infer(()) => String::new(),
             TyKind::Ptr(mut_ty) => {
                 if matches!(mut_ty.ty.kind, TyKind::Infer(())) {
@@ -58,16 +63,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv)
         // following `cast` does not compile because it fails to infer what type is expected
         // as type argument to `std::ptr::ptr_null` or `std::ptr::ptr_null_mut`, so
         // we omit following `cast`:
-        let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind
+        let omit_cast = if let ExprKind::Call(func, []) = cast_from_expr.kind
             && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind
             && let Some(method_defid) = path.res.opt_def_id()
         {
-            if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) {
-                OmitFollowedCastReason::Null(qpath)
-            } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) {
-                OmitFollowedCastReason::NullMut(qpath)
-            } else {
-                OmitFollowedCastReason::None
+            match cx.tcx.get_diagnostic_name(method_defid) {
+                Some(sym::ptr_null) => OmitFollowedCastReason::Null(qpath),
+                Some(sym::ptr_null_mut) => OmitFollowedCastReason::NullMut(qpath),
+                _ => OmitFollowedCastReason::None,
             }
         } else {
             OmitFollowedCastReason::None
@@ -78,7 +81,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv)
             let method = snippet_with_applicability(cx, qpath_span_without_turbofish(method), "..", &mut app);
             ("try call directly", format!("{method}{turbofish}()"))
         } else {
-            let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
+            let cast_expr_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "_", &mut app);
 
             (
                 "try `pointer::cast`, a safer alternative",
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index c0c0a47f855..c0f13f5e578 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{std_or_core, sym};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Mutability, QPath};
+use rustc_hir::{self as hir, Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
@@ -12,26 +13,23 @@ use super::PTR_CAST_CONSTNESS;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'_>,
     expr: &Expr<'_>,
-    cast_expr: &Expr<'_>,
+    cast_from_expr: &Expr<'_>,
     cast_from: Ty<'tcx>,
     cast_to: Ty<'tcx>,
     msrv: Msrv,
 ) {
     if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind()
         && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind()
-        && matches!(
-            (from_mutbl, to_mutbl),
-            (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)
-        )
+        && from_mutbl != to_mutbl
         && from_ty == to_ty
         && !from_ty.has_erased_regions()
     {
-        if let ExprKind::Call(func, []) = cast_expr.kind
+        if let ExprKind::Call(func, []) = cast_from_expr.kind
             && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
             && let Some(defid) = path.res.opt_def_id()
             && let Some(prefix) = std_or_core(cx)
             && let mut app = Applicability::MachineApplicable
-            && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app))
+            && let sugg = snippet_with_applicability(cx, cast_from_expr.span, "_", &mut app)
             && let Some((_, after_lt)) = sugg.split_once("::<")
             && let Some((source, target, target_func)) = match cx.tcx.get_diagnostic_name(defid) {
                 Some(sym::ptr_null) => Some(("const", "mutable", "null_mut")),
@@ -53,11 +51,17 @@ pub(super) fn check<'tcx>(
 
         if msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) {
             let mut app = Applicability::MachineApplicable;
-            let sugg = Sugg::hir_with_context(cx, cast_expr, expr.span.ctxt(), "_", &mut app);
-            let constness = match *to_mutbl {
-                Mutability::Not => "const",
-                Mutability::Mut => "mut",
+            let sugg = if let ExprKind::Cast(nested_from, nested_hir_ty) = cast_from_expr.kind
+                && let hir::TyKind::Ptr(ptr_ty) = nested_hir_ty.kind
+                && let hir::TyKind::Infer(()) = ptr_ty.ty.kind
+            {
+                // `(foo as *const _).cast_mut()` fails method name resolution
+                // avoid this by `as`-ing the full type
+                Sugg::hir_with_context(cx, nested_from, expr.span.ctxt(), "_", &mut app).as_ty(cast_from)
+            } else {
+                Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "_", &mut app)
             };
+            let constness = to_mutbl.ptr_str();
 
             span_lint_and_sugg(
                 cx,
@@ -73,8 +77,8 @@ pub(super) fn check<'tcx>(
 }
 
 pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) {
-    if let ExprKind::MethodCall(method, cast_expr, [], _) = expr.kind
-        && let ExprKind::Call(func, []) = cast_expr.kind
+    if let ExprKind::MethodCall(method, cast_from_expr, [], _) = expr.kind
+        && let ExprKind::Call(func, []) = cast_from_expr.kind
         && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
         && let Some(defid) = path.res.opt_def_id()
         && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.name) {
@@ -84,7 +88,7 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>)
         }
         && let Some(prefix) = std_or_core(cx)
         && let mut app = Applicability::MachineApplicable
-        && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app))
+        && let sugg = snippet_with_applicability(cx, cast_from_expr.span, "_", &mut app)
         && let Some((_, after_lt)) = sugg.split_once("::<")
     {
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 8f95c63a854..7646aa48b77 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -23,8 +23,8 @@ declare_clippy_lint! {
     ///
     /// ### Known problems
     /// The true Cognitive Complexity of a method is not something we can
-    /// calculate using modern technology. This lint has been left in the
-    /// `nursery` so as to not mislead users into using this lint as a
+    /// calculate using modern technology. This lint has been left in
+    /// `restriction` so as to not mislead users into using this lint as a
     /// measurement tool.
     ///
     /// For more detailed information, see [rust-clippy#3793](https://github.com/rust-lang/rust-clippy/issues/3793)
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index e67e8d9070f..d0c7443a4a4 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -35,6 +35,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO,
     crate::blocks_in_conditions::BLOCKS_IN_CONDITIONS_INFO,
     crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO,
+    crate::bool_comparison::BOOL_COMPARISON_INFO,
     crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
     crate::booleans::NONMINIMAL_BOOL_INFO,
     crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
@@ -538,7 +539,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::mutex_atomic::MUTEX_ATOMIC_INFO,
     crate::mutex_atomic::MUTEX_INTEGER_INFO,
     crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
-    crate::needless_bool::BOOL_COMPARISON_INFO,
     crate::needless_bool::NEEDLESS_BOOL_INFO,
     crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO,
     crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 7580d6cab66..06c2393e0a3 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
-use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty, TypeckResults};
+use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty, TypeckResults, VariantDef};
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
 
@@ -85,6 +85,13 @@ fn contains_trait_object(ty: Ty<'_>) -> bool {
     }
 }
 
+fn determine_derive_macro(cx: &LateContext<'_>, is_const: bool) -> Option<&'static str> {
+    (!is_const)
+        .then_some("derive")
+        .or_else(|| cx.tcx.features().enabled(sym::derive_const).then_some("derive_const"))
+}
+
+#[expect(clippy::too_many_arguments)]
 fn check_struct<'tcx>(
     cx: &LateContext<'tcx>,
     item: &'tcx Item<'_>,
@@ -93,6 +100,7 @@ fn check_struct<'tcx>(
     adt_def: AdtDef<'_>,
     ty_args: GenericArgsRef<'_>,
     typeck_results: &'tcx TypeckResults<'tcx>,
+    is_const: bool,
 ) {
     if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind
         && let Some(PathSegment { args, .. }) = p.segments.last()
@@ -125,14 +133,18 @@ fn check_struct<'tcx>(
         ExprKind::Tup(fields) => fields.iter().all(is_default_without_adjusts),
         ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(is_default_without_adjusts),
         ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_without_adjusts(ef.expr)),
-        _ => false,
+        _ => return,
     };
 
-    if should_emit {
+    if should_emit && let Some(derive_snippet) = determine_derive_macro(cx, is_const) {
         let struct_span = cx.tcx.def_span(adt_def.did());
+        let indent_enum = indent_of(cx, struct_span).unwrap_or(0);
         let suggestions = vec![
             (item.span, String::new()), // Remove the manual implementation
-            (struct_span.shrink_to_lo(), "#[derive(Default)]\n".to_string()), // Add the derive attribute
+            (
+                struct_span.shrink_to_lo(),
+                format!("#[{derive_snippet}(Default)]\n{}", " ".repeat(indent_enum)),
+            ), // Add the derive attribute
         ];
 
         span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
@@ -145,11 +157,41 @@ fn check_struct<'tcx>(
     }
 }
 
-fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) {
-    if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind
-        && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res
-        && let variant_id = cx.tcx.parent(id)
-        && let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id)
+fn extract_enum_variant<'tcx>(
+    cx: &LateContext<'tcx>,
+    func_expr: &'tcx Expr<'tcx>,
+    adt_def: AdtDef<'tcx>,
+) -> Option<&'tcx VariantDef> {
+    match &peel_blocks(func_expr).kind {
+        ExprKind::Path(QPath::Resolved(None, p))
+            if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res
+                && let variant_id = cx.tcx.parent(id)
+                && let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id) =>
+        {
+            Some(variant_def)
+        },
+        ExprKind::Path(QPath::TypeRelative(ty, segment))
+            if let TyKind::Path(QPath::Resolved(None, p)) = &ty.kind
+                && let Res::SelfTyAlias {
+                    is_trait_impl: true, ..
+                } = p.res
+                && let variant_ident = segment.ident
+                && let Some(variant_def) = adt_def.variants().iter().find(|v| v.ident(cx.tcx) == variant_ident) =>
+        {
+            Some(variant_def)
+        },
+        _ => None,
+    }
+}
+
+fn check_enum<'tcx>(
+    cx: &LateContext<'tcx>,
+    item: &'tcx Item<'tcx>,
+    func_expr: &'tcx Expr<'tcx>,
+    adt_def: AdtDef<'tcx>,
+    is_const: bool,
+) {
+    if let Some(variant_def) = extract_enum_variant(cx, func_expr, adt_def)
         && variant_def.fields.is_empty()
         && !variant_def.is_field_list_non_exhaustive()
     {
@@ -158,11 +200,15 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex
         let variant_span = cx.tcx.def_span(variant_def.def_id);
         let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
 
+        let Some(derive_snippet) = determine_derive_macro(cx, is_const) else {
+            return;
+        };
+
         let suggestions = vec![
             (item.span, String::new()), // Remove the manual implementation
             (
                 enum_span.shrink_to_lo(),
-                format!("#[derive(Default)]\n{}", " ".repeat(indent_enum)),
+                format!("#[{derive_snippet}(Default)]\n{}", " ".repeat(indent_enum)),
             ), // Add the derive attribute
             (
                 variant_span.shrink_to_lo(),
@@ -201,10 +247,20 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
             && !attrs.iter().any(|attr| attr.doc_str().is_some())
             && cx.tcx.hir_attrs(impl_item_hir).is_empty()
         {
+            let is_const = of_trait.constness == hir::Constness::Const;
             if adt_def.is_struct() {
-                check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b));
+                check_struct(
+                    cx,
+                    item,
+                    self_ty,
+                    func_expr,
+                    adt_def,
+                    args,
+                    cx.tcx.typeck_body(*b),
+                    is_const,
+                );
             } else if adt_def.is_enum() && self.msrv.meets(cx, msrvs::DEFAULT_ENUM_ATTRIBUTE) {
-                check_enum(cx, item, func_expr, adt_def);
+                check_enum(cx, item, func_expr, adt_def, is_const);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 182cb4e46d2..a5ec6777b43 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context};
 use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_expr;
@@ -194,7 +194,17 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
         if let Some(sugg) = sugg {
             span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app);
         } else {
-            span_lint(cx, MAP_ENTRY, expr.span, lint_msg);
+            span_lint_and_help(
+                cx,
+                MAP_ENTRY,
+                expr.span,
+                lint_msg,
+                None,
+                format!(
+                    "consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.{}.html#entry-api",
+                    map_ty.name()
+                ),
+            );
         }
     }
 }
@@ -254,35 +264,28 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
         _ => None,
     });
 
-    match expr.kind {
-        ExprKind::MethodCall(
-            _,
+    if let ExprKind::MethodCall(_, map, [arg], _) = expr.kind
+        && let Expr {
+            kind: ExprKind::AddrOf(_, _, key),
+            span: key_span,
+            ..
+        } = arg
+        && key_span.eq_ctxt(expr.span)
+    {
+        let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
+        let expr = ContainsExpr {
+            negated,
             map,
-            [
-                Expr {
-                    kind: ExprKind::AddrOf(_, _, key),
-                    span: key_span,
-                    ..
-                },
-            ],
-            _,
-        ) if key_span.eq_ctxt(expr.span) => {
-            let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
-            let expr = ContainsExpr {
-                negated,
-                map,
-                key,
-                call_ctxt: expr.span.ctxt(),
-            };
-            if cx.tcx.is_diagnostic_item(sym::btreemap_contains_key, id) {
-                Some((MapType::BTree, expr))
-            } else if cx.tcx.is_diagnostic_item(sym::hashmap_contains_key, id) {
-                Some((MapType::Hash, expr))
-            } else {
-                None
-            }
-        },
-        _ => None,
+            key,
+            call_ctxt: expr.span.ctxt(),
+        };
+        match cx.tcx.get_diagnostic_name(id) {
+            Some(sym::btreemap_contains_key) => Some((MapType::BTree, expr)),
+            Some(sym::hashmap_contains_key) => Some((MapType::Hash, expr)),
+            _ => None,
+        }
+    } else {
+        None
     }
 }
 
@@ -311,7 +314,9 @@ struct InsertExpr<'tcx> {
 fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
     if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
         let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
-        if cx.tcx.is_diagnostic_item(sym::btreemap_insert, id) || cx.tcx.is_diagnostic_item(sym::hashmap_insert, id) {
+        if let Some(insert) = cx.tcx.get_diagnostic_name(id)
+            && matches!(insert, sym::btreemap_insert | sym::hashmap_insert)
+        {
             Some(InsertExpr { map, key, value })
         } else {
             None
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 0eefc2f6109..2da1c2bad11 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -12,6 +12,7 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind, find_attr};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{
     self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
 };
@@ -148,10 +149,9 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
             {
                 return;
             }
-            let callee_ty_adjusted = typeck
-                .expr_adjustments(callee)
-                .last()
-                .map_or(callee_ty, |a| a.target.peel_refs());
+
+            let callee_ty_adjustments = typeck.expr_adjustments(callee);
+            let callee_ty_adjusted = callee_ty_adjustments.last().map_or(callee_ty, |a| a.target);
 
             let sig = match callee_ty_adjusted.kind() {
                 ty::FnDef(def, _) => {
@@ -230,7 +230,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                                     },
                                     _ => (),
                                 }
+                            } else if let n_refs =
+                                callee_ty_adjustments
+                                    .iter()
+                                    .rev()
+                                    .fold(0, |acc, adjustment| match adjustment.kind {
+                                        Adjust::Deref(Some(_)) => acc + 1,
+                                        Adjust::Deref(_) if acc > 0 => acc + 1,
+                                        _ => acc,
+                                    })
+                                && n_refs > 0
+                            {
+                                snippet = format!("{}{snippet}", "*".repeat(n_refs));
                             }
+
                             let replace_with = match callee_ty_adjusted.kind() {
                                 ty::FnDef(def, _) => cx.tcx.def_descr(*def),
                                 _ => "function",
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index ccaf38aee4d..6178addfff1 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -1,11 +1,12 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::numeric_literal;
+use clippy_utils::{ExprUseNode, expr_use_ctxt, numeric_literal};
 use rustc_ast::ast::{LitFloatType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, FloatTy};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use std::fmt;
 
 declare_clippy_lint! {
@@ -13,6 +14,8 @@ declare_clippy_lint! {
     /// Checks for float literals with a precision greater
     /// than that supported by the underlying type.
     ///
+    /// The lint is suppressed for literals with over `const_literal_digits_threshold` digits.
+    ///
     /// ### Why is this bad?
     /// Rust will truncate the literal silently.
     ///
@@ -58,7 +61,21 @@ declare_clippy_lint! {
     "lossy whole number float literals"
 }
 
-declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]);
+pub struct FloatLiteral {
+    const_literal_digits_threshold: usize,
+}
+
+impl_lint_pass!(FloatLiteral => [
+    EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL
+]);
+
+impl FloatLiteral {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            const_literal_digits_threshold: conf.const_literal_digits_threshold,
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
@@ -126,13 +143,25 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
                         },
                     );
                 }
-            } else if digits > max as usize && count_digits(&float_str) < count_digits(sym_str) {
+            } else if digits > max as usize && count_digits(&float_str) < digits {
+                if digits >= self.const_literal_digits_threshold
+                    && matches!(expr_use_ctxt(cx, expr).use_node(cx), ExprUseNode::ConstStatic(_))
+                {
+                    // If a big enough number of digits is specified and it's a constant
+                    // we assume the user is definining a constant, and excessive precision is ok
+                    return;
+                }
                 span_lint_and_then(
                     cx,
                     EXCESSIVE_PRECISION,
                     expr.span,
                     "float has excessive precision",
                     |diag| {
+                        if digits >= self.const_literal_digits_threshold
+                            && let Some(let_stmt) = maybe_let_stmt(cx, expr)
+                        {
+                            diag.span_note(let_stmt.span, "consider making it a `const` item");
+                        }
                         diag.span_suggestion_verbose(
                             expr.span,
                             "consider changing the type or truncating it to",
@@ -196,3 +225,11 @@ impl FloatFormat {
         }
     }
 }
+
+fn maybe_let_stmt<'a>(cx: &LateContext<'a>, expr: &hir::Expr<'_>) -> Option<&'a hir::LetStmt<'a>> {
+    let parent = cx.tcx.parent_hir_node(expr.hir_id);
+    match parent {
+        hir::Node::LetStmt(let_stmt) => Some(let_stmt),
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ca5ea901814..5a40af42194 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -535,7 +535,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         def_id: LocalDefId,
     ) {
         let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-        too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
+        too_many_arguments::check_fn(cx, kind, decl, hir_id, def_id, self.too_many_arguments_threshold);
         too_many_lines::check_fn(cx, kind, body, span, def_id, self.too_many_lines_threshold);
         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
         misnamed_getters::check_fn(cx, kind, decl, body, span);
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
index 48d050aa36a..6c3c3d354ec 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
@@ -1,5 +1,7 @@
 use rustc_abi::ExternAbi;
-use rustc_hir::{self as hir, intravisit};
+use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
@@ -10,39 +12,18 @@ use super::TOO_MANY_ARGUMENTS;
 
 pub(super) fn check_fn(
     cx: &LateContext<'_>,
-    kind: intravisit::FnKind<'_>,
+    kind: FnKind<'_>,
     decl: &hir::FnDecl<'_>,
-    span: Span,
     hir_id: hir::HirId,
+    def_id: LocalDefId,
     too_many_arguments_threshold: u64,
 ) {
     // don't warn for implementations, it's not their fault
-    if !is_trait_impl_item(cx, hir_id) {
+    if !is_trait_impl_item(cx, hir_id)
         // don't lint extern functions decls, it's not their fault either
-        match kind {
-            intravisit::FnKind::Method(
-                _,
-                &hir::FnSig {
-                    header: hir::FnHeader {
-                        abi: ExternAbi::Rust, ..
-                    },
-                    ..
-                },
-            )
-            | intravisit::FnKind::ItemFn(
-                _,
-                _,
-                hir::FnHeader {
-                    abi: ExternAbi::Rust, ..
-                },
-            ) => check_arg_number(
-                cx,
-                decl,
-                span.with_hi(decl.output.span().hi()),
-                too_many_arguments_threshold,
-            ),
-            _ => {},
-        }
+        && kind.header().is_some_and(|header| header.abi == ExternAbi::Rust)
+    {
+        check_arg_number(cx, decl, cx.tcx.def_span(def_id), too_many_arguments_threshold);
     }
 }
 
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 7158f9419c1..b50d91f1014 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
@@ -2,16 +2,16 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::snippet_with_context;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor,
-    path_res, peel_blocks,
+    path_res, peel_blocks, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -71,21 +71,21 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && let ExprKind::Block(then_block, _) = then.kind
             && let Some(then_expr) = then_block.expr
             && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
-            && let ctxt = expr.span.ctxt()
-            && then_expr.span.ctxt() == ctxt
+            && !expr.span.from_expansion()
+            && !then_expr.span.from_expansion()
             && 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)
             && !is_in_const_context(cx)
-            && !expr.span.in_external_macro(cx.sess().source_map())
             && self.msrv.meets(cx, msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
         {
             let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) {
-                "then_some"
+                sym::then_some
             } else {
-                "then"
+                sym::then
             };
+            let ctxt = expr.span.ctxt();
 
             span_lint_and_then(
                 cx,
@@ -98,16 +98,18 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
                     }
 
                     let mut app = Applicability::MachineApplicable;
-                    let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
+                    let cond_snip = Sugg::hir_with_context(cx, cond, ctxt, "[condition]", &mut app)
                         .maybe_paren()
                         .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 if method_name == "then" {
+                    let method_body = if let Some(first_stmt) = then_block.stmts.first()
+                        && let Some(first_stmt_span) = walk_span_to_context(first_stmt.span, ctxt)
+                    {
+                        let block_snippet =
+                            snippet_with_applicability(cx, first_stmt_span.until(then_expr.span), "..", &mut app);
+                        let closure = if method_name == sym::then { "|| " } else { "" };
+                        format!("{closure} {{ {} {arg_snip} }}", block_snippet.trim_end())
+                    } else if method_name == sym::then {
                         (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned()
                     } else {
                         arg_snip.into_owned()
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 91f65d0b79c..13117f60abd 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty;
+use clippy_utils::{is_path_diagnostic_item, ty};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -107,8 +107,7 @@ impl LateLintPass<'_> for InstantSubtraction {
 
 fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
     if let ExprKind::Call(fn_expr, []) = expr_block.kind
-        && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
-        && cx.tcx.is_diagnostic_item(sym::instant_now, fn_id)
+        && is_path_diagnostic_item(cx, fn_expr, sym::instant_now)
     {
         true
     } else {
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 8707612fbdd..48ce1afc6e6 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -64,8 +64,8 @@ impl LateLintPass<'_> for LargeIncludeFile {
             }
             && len as u64 > self.max_file_size
             && let Some(macro_call) = root_macro_call_first_node(cx, expr)
-            && (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))
+            && let Some(macro_name) = cx.tcx.get_diagnostic_name(macro_call.def_id)
+            && matches!(macro_name, sym::include_bytes_macro | sym::include_str_macro)
         {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 57deb011f2b..f44a5fdf715 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -355,12 +355,15 @@ fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<Le
             return Some(LenOutput::Integral);
         }
 
-        if let Res::Def(_, def_id) = res {
-            if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_first_generic_integral(segment) {
-                return Some(LenOutput::Option(def_id));
-            } else if cx.tcx.is_diagnostic_item(sym::Result, def_id) && is_first_generic_integral(segment) {
-                return Some(LenOutput::Result(def_id));
+        if let Res::Def(_, def_id) = res
+            && let Some(res) = match cx.tcx.get_diagnostic_name(def_id) {
+                Some(sym::Option) => Some(LenOutput::Option(def_id)),
+                Some(sym::Result) => Some(LenOutput::Result(def_id)),
+                _ => None,
             }
+            && is_first_generic_integral(segment)
+        {
+            return Some(res);
         }
 
         return None;
@@ -368,11 +371,10 @@ fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<Le
 
     match *sig.output().kind() {
         ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
-        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) => {
-            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did()))
-        },
-        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => {
-            subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did()))
+        ty::Adt(adt, subs) if subs.type_at(0).is_integral() => match cx.tcx.get_diagnostic_name(adt.did()) {
+            Some(sym::Option) => Some(LenOutput::Option(adt.did())),
+            Some(sym::Result) => Some(LenOutput::Result(adt.did())),
+            _ => None,
         },
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index c8594cf35e2..a89cf3fdc1e 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -84,6 +84,7 @@ mod attrs;
 mod await_holding_invalid;
 mod blocks_in_conditions;
 mod bool_assert_comparison;
+mod bool_comparison;
 mod bool_to_int_with_if;
 mod booleans;
 mod borrow_deref_ref;
@@ -474,10 +475,10 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(move |_| Box::new(types::Types::new(conf)));
     store.register_late_pass(move |_| Box::new(booleans::NonminimalBool::new(conf)));
     store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
-    store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
+    store.register_late_pass(move |_| Box::new(float_literal::FloatLiteral::new(conf)));
     store.register_late_pass(|_| Box::new(ptr::Ptr));
     store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
-    store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
+    store.register_late_pass(|_| Box::new(bool_comparison::BoolComparison));
     store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
     store.register_late_pass(|_| Box::new(misc::LintPass));
     store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
@@ -655,7 +656,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(conf)));
     store.register_late_pass(|_| Box::<macro_use::MacroUseImports>::default());
     store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
-    store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
+    store.register_late_pass(|_| Box::<unwrap_in_result::UnwrapInResult>::default());
     store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
     store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
     let attrs = attr_storage.clone();
diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
index a71e6963f8c..74c0b178018 100644
--- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
@@ -4,7 +4,8 @@ use hir::intravisit::{Visitor, walk_expr};
 use rustc_ast::Label;
 use rustc_errors::Applicability;
 use rustc_hir::{
-    self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Expr, ExprKind, FnRetTy, FnSig, Node, TyKind,
+    self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnRetTy,
+    FnSig, Node, TyKind,
 };
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::sym;
@@ -73,7 +74,11 @@ fn is_inside_unawaited_async_block(cx: &LateContext<'_>, expr: &Expr<'_>) -> boo
         if let Node::Expr(Expr {
             kind:
                 ExprKind::Closure(Closure {
-                    kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
+                    kind:
+                        ClosureKind::Coroutine(CoroutineKind::Desugared(
+                            CoroutineDesugaring::Async,
+                            CoroutineSource::Block | CoroutineSource::Closure,
+                        )),
                     ..
                 }),
             ..
diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
index a9944d64ce2..8a2d0036203 100644
--- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
@@ -1,10 +1,10 @@
 use super::MISSING_SPIN_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::std_or_core;
+use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
 use rustc_span::sym;
 
 fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
@@ -39,8 +39,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
     ) = body.kind
         && let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind
         && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
-        && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind()
-        && cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did())
+        && let callee_ty = cx.typeck_results().expr_ty(callee)
+        && is_type_diagnostic_item(cx, callee_ty, sym::AtomicBool)
         && let Some(std_or_core) = std_or_core(cx)
     {
         span_lint_and_sugg(
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 7bb684d65bb..11edb929d70 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
@@ -3,7 +3,7 @@ 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::{SpanlessEq, contains_name, higher, is_integer_const, sugg};
+use clippy_utils::{SpanlessEq, contains_name, higher, is_integer_const, peel_hir_expr_while, sugg};
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
@@ -253,12 +253,38 @@ struct VarVisitor<'a, 'tcx> {
 
 impl<'tcx> VarVisitor<'_, 'tcx> {
     fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
-        let index_used_directly = matches!(idx.kind, ExprKind::Path(_));
+        let mut used_cnt = 0;
+        // It is `true` if all indices are direct
+        let mut index_used_directly = true;
+
+        // Handle initial index
+        if is_local_used(self.cx, idx, self.var) {
+            used_cnt += 1;
+            index_used_directly &= matches!(idx.kind, ExprKind::Path(_));
+        }
+        // Handle nested indices
+        let seqexpr = peel_hir_expr_while(seqexpr, |e| {
+            if let ExprKind::Index(e, idx, _) = e.kind {
+                if is_local_used(self.cx, idx, self.var) {
+                    used_cnt += 1;
+                    index_used_directly &= matches!(idx.kind, ExprKind::Path(_));
+                }
+                Some(e)
+            } else {
+                None
+            }
+        });
+
+        match used_cnt {
+            0 => return true,
+            n if n > 1 => self.nonindex = true, // Optimize code like `a[i][i]`
+            _ => {},
+        }
+
         if let ExprKind::Path(ref seqpath) = seqexpr.kind
             // the indexed container is referenced by a name
             && let QPath::Resolved(None, seqvar) = *seqpath
             && seqvar.segments.len() == 1
-            && is_local_used(self.cx, idx, self.var)
         {
             if self.prefer_mutable {
                 self.indexed_mut.insert(seqvar.segments[0].ident.name);
@@ -312,7 +338,6 @@ impl<'tcx> VarVisitor<'_, 'tcx> {
 impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind
-            // a range index op
             && let Some(trait_id) = self
                 .cx
                 .typeck_results()
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 51e21aa9734..13b93d2c009 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,12 +1,12 @@
 use super::UNUSED_ENUMERATE_INDEX;
 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::def::DefKind;
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
 use rustc_span::sym;
 
 /// Checks for the `UNUSED_ENUMERATE_INDEX` lint.
@@ -17,8 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_
         && let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind
         && let ty = cx.typeck_results().expr_ty(arg)
         && pat_is_wild(cx, &index.kind, body)
-        && let ty::Adt(base, _) = *ty.kind()
-        && cx.tcx.is_diagnostic_item(sym::Enumerate, base.did())
+        && is_type_diagnostic_item(cx, ty, sym::Enumerate)
         && let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id)
         && cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id)
     {
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 ac8c88f0205..2eebb2430fd 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
@@ -97,11 +97,12 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             return;
         }
 
-        if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) {
-            if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
-                let range = check_pat(&arm.pat.kind);
-                check_is_ascii(cx, macro_call.span, recv, &range, None);
-            }
+        let (arg, span, range) = if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro)
+            && let ExprKind::Match(recv, [arm, ..], _) = expr.kind
+        {
+            let recv = peel_ref_operators(cx, recv);
+            let range = check_pat(&arm.pat.kind);
+            (recv, macro_call.span, range)
         } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
             && path.ident.name == sym::contains
             && let Some(higher::Range {
@@ -112,10 +113,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
         {
             let arg = peel_ref_operators(cx, arg);
-            let ty_sugg = get_ty_sugg(cx, arg);
             let range = check_expr_range(start, end);
-            check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
-        }
+            (arg, expr.span, range)
+        } else {
+            return;
+        };
+
+        let ty_sugg = get_ty_sugg(cx, arg);
+        check_is_ascii(cx, span, arg, &range, ty_sugg);
     }
 }
 
@@ -146,9 +151,8 @@ fn check_is_ascii(
         CharRange::HexDigit => "is_ascii_hexdigit",
         CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => return,
     };
-    let default_snip = "..";
     let mut app = Applicability::MachineApplicable;
-    let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_paren();
+    let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), "_", &mut app).maybe_paren();
     let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))];
     if let Some((ty_span, ty)) = ty_sugg {
         suggestion.push((ty_span, format!("{recv}: {ty}")));
@@ -182,7 +186,7 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
                 CharRange::Otherwise
             }
         },
-        PatKind::Range(Some(start), Some(end), kind) if *kind == RangeEnd::Included => check_range(start, end),
+        PatKind::Range(Some(start), Some(end), RangeEnd::Included) => check_range(start, end),
         _ => CharRange::Otherwise,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 98e8b1f5cf9..7fb88763e64 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -123,8 +123,8 @@ fn check_iter(
 ) {
     if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
         && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
-        && (cx.tcx.is_diagnostic_item(sym::iter_copied, copied_def_id)
-            || cx.tcx.is_diagnostic_item(sym::iter_cloned, copied_def_id))
+        && let Some(copied_name) = cx.tcx.get_diagnostic_name(copied_def_id)
+        && matches!(copied_name, sym::iter_copied | sym::iter_cloned)
         && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
         && cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id)
@@ -243,9 +243,9 @@ fn make_sugg(
 }
 
 fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool {
-    ACCEPTABLE_METHODS
-        .iter()
-        .any(|&method| cx.tcx.is_diagnostic_item(method, collect_def_id))
+    cx.tcx
+        .get_diagnostic_name(collect_def_id)
+        .is_some_and(|collect_name| ACCEPTABLE_METHODS.contains(&collect_name))
 }
 
 fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 6bf43a1c6d4..07cce4046ca 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -75,12 +75,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
             && let ExprKind::Path(target_path) = &target_arg.kind
             && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
         {
-            let strip_kind = if cx.tcx.is_diagnostic_item(sym::str_starts_with, method_def_id) {
-                StripKind::Prefix
-            } else if cx.tcx.is_diagnostic_item(sym::str_ends_with, method_def_id) {
-                StripKind::Suffix
-            } else {
-                return;
+            let strip_kind = match cx.tcx.get_diagnostic_name(method_def_id) {
+                Some(sym::str_starts_with) => StripKind::Prefix,
+                Some(sym::str_ends_with) => StripKind::Suffix,
+                _ => return,
             };
             let target_res = cx.qpath_res(target_path, target_arg.hir_id);
             if target_res == Res::Err {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index af6a1b07a49..39e5289c62a 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -116,8 +116,10 @@ fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 /// The expression inside a closure may or may not have surrounding braces and
 /// semicolons, which causes problems when generating a suggestion. Given an
 /// expression that evaluates to '()' or '!', recursively remove useless braces
-/// and semi-colons until is suitable for including in the suggestion template
-fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Span> {
+/// and semi-colons until is suitable for including in the suggestion template.
+/// The `bool` is `true` when the resulting `span` needs to be enclosed in an
+/// `unsafe` block.
+fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<(Span, bool)> {
     if !is_unit_expression(cx, expr) {
         return None;
     }
@@ -125,22 +127,24 @@ fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<
     match expr.kind {
         hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(..) => {
             // Calls can't be reduced any more
-            Some(expr.span)
+            Some((expr.span, false))
         },
         hir::ExprKind::Block(block, _) => {
+            let is_unsafe = matches!(block.rules, hir::BlockCheckMode::UnsafeBlock(_));
             match (block.stmts, block.expr.as_ref()) {
                 ([], Some(inner_expr)) => {
                     // If block only contains an expression,
                     // reduce `{ X }` to `X`
                     reduce_unit_expression(cx, inner_expr)
+                        .map(|(span, inner_is_unsafe)| (span, inner_is_unsafe || is_unsafe))
                 },
                 ([inner_stmt], None) => {
                     // If block only contains statements,
                     // reduce `{ X; }` to `X` or `X;`
                     match inner_stmt.kind {
-                        hir::StmtKind::Let(local) => Some(local.span),
-                        hir::StmtKind::Expr(e) => Some(e.span),
-                        hir::StmtKind::Semi(..) => Some(inner_stmt.span),
+                        hir::StmtKind::Let(local) => Some((local.span, is_unsafe)),
+                        hir::StmtKind::Expr(e) => Some((e.span, is_unsafe)),
+                        hir::StmtKind::Semi(..) => Some((inner_stmt.span, is_unsafe)),
                         hir::StmtKind::Item(..) => None,
                     }
                 },
@@ -228,10 +232,11 @@ fn lint_map_unit_fn(
         let msg = suggestion_msg("closure", map_type);
 
         span_lint_and_then(cx, lint, expr.span, msg, |diag| {
-            if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
+            if let Some((reduced_expr_span, is_unsafe)) = reduce_unit_expression(cx, closure_expr) {
                 let mut applicability = Applicability::MachineApplicable;
+                let (prefix_is_unsafe, suffix_is_unsafe) = if is_unsafe { ("unsafe { ", " }") } else { ("", "") };
                 let suggestion = format!(
-                    "if let {0}({1}) = {2} {{ {3} }}",
+                    "if let {0}({1}) = {2} {{ {prefix_is_unsafe}{3}{suffix_is_unsafe} }}",
                     variant,
                     snippet_with_applicability(cx, binding.pat.span, "_", &mut applicability),
                     snippet_with_applicability(cx, var_arg.span, "_", &mut applicability),
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 5b50efad3e4..aaf559fc443 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -4,20 +4,22 @@ use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{
-    SpanlessEq, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators,
+    SpanlessEq, get_ref_operators, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt,
+    peel_ref_operators,
 };
+use rustc_ast::BorrowKind;
 use rustc_errors::MultiSpan;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, HirId, Pat, PatExpr, PatExprKind, PatKind};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
 use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or};
 
-pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: Msrv) {
+pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>], msrv: Msrv) {
     if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) {
         for arm in arms {
-            check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body), msrv);
+            check_arm(cx, true, arm.pat, expr, arm.body, arm.guard, Some(els_arm.body), msrv);
         }
     }
 }
@@ -27,15 +29,18 @@ pub(super) fn check_if_let<'tcx>(
     pat: &'tcx Pat<'_>,
     body: &'tcx Expr<'_>,
     else_expr: Option<&'tcx Expr<'_>>,
+    let_expr: &'tcx Expr<'_>,
     msrv: Msrv,
 ) {
-    check_arm(cx, false, pat, body, None, else_expr, msrv);
+    check_arm(cx, false, pat, let_expr, body, None, else_expr, msrv);
 }
 
+#[allow(clippy::too_many_arguments)]
 fn check_arm<'tcx>(
     cx: &LateContext<'tcx>,
     outer_is_match: bool,
     outer_pat: &'tcx Pat<'tcx>,
+    outer_cond: &'tcx Expr<'tcx>,
     outer_then_body: &'tcx Expr<'tcx>,
     outer_guard: Option<&'tcx Expr<'tcx>>,
     outer_else_body: Option<&'tcx Expr<'tcx>>,
@@ -82,6 +87,9 @@ fn check_arm<'tcx>(
             },
             IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),
         }
+        // Check if the inner expression contains any borrows/dereferences
+        && let ref_types = get_ref_operators(cx, inner_scrutinee)
+        && let Some(method) = build_ref_method_chain(ref_types)
     {
         let msg = format!(
             "this `{}` can be collapsed into the outer `{}`",
@@ -103,6 +111,10 @@ fn check_arm<'tcx>(
             let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
             help_span.push_span_label(binding_span, "replace this binding");
             help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
+            if !method.is_empty() {
+                let outer_cond_msg = format!("use: `{}{}`", snippet(cx, outer_cond.span, ".."), method);
+                help_span.push_span_label(outer_cond.span, outer_cond_msg);
+            }
             diag.span_help(
                 help_span,
                 "the outer pattern can be modified to include the inner pattern",
@@ -148,3 +160,30 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi
     });
     (span, is_innermost_parent_pat_struct)
 }
+
+/// Builds a chain of reference-manipulation method calls (e.g., `.as_ref()`, `.as_mut()`,
+/// `.copied()`) based on reference operators
+fn build_ref_method_chain(expr: Vec<&Expr<'_>>) -> Option<String> {
+    let mut req_method_calls = String::new();
+
+    for ref_operator in expr {
+        match ref_operator.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, _) => {
+                return None;
+            },
+            ExprKind::AddrOf(_, m, _) if m.is_mut() => {
+                req_method_calls.push_str(".as_mut()");
+            },
+            ExprKind::AddrOf(_, _, _) => {
+                req_method_calls.push_str(".as_ref()");
+            },
+            // Deref operator is the only operator that this function should have received
+            ExprKind::Unary(_, _) => {
+                req_method_calls.push_str(".copied()");
+            },
+            _ => (),
+        }
+    }
+
+    Some(req_method_calls)
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index c128fc40b73..6f49c552411 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1073,7 +1073,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source);
             }
 
-            collapsible_match::check_match(cx, arms, self.msrv);
+            collapsible_match::check_match(cx, ex, arms, self.msrv);
             if !from_expansion {
                 // These don't depend on a relationship between multiple arms
                 match_wild_err_arm::check(cx, ex, arms);
@@ -1137,7 +1137,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr);
             }
         } else if let Some(if_let) = higher::IfLet::hir(cx, expr) {
-            collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, self.msrv);
+            collapsible_match::check_if_let(
+                cx,
+                if_let.let_pat,
+                if_let.if_then,
+                if_let.if_else,
+                if_let.let_expr,
+                self.msrv,
+            );
             significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else);
             if !from_expansion {
                 if let Some(else_expr) = if_let.if_else {
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 027dd7ce053..81fecc87256 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -226,11 +226,12 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
 enum SigDropHolder {
     /// No values with significant drop present in this expression.
     ///
     /// Expressions that we've emitted lints do not count.
+    #[default]
     None,
     /// Some field in this expression references to values with significant drop.
     ///
@@ -244,12 +245,6 @@ enum SigDropHolder {
     Moved,
 }
 
-impl Default for SigDropHolder {
-    fn default() -> Self {
-        Self::None
-    }
-}
-
 struct SigDropHelper<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     parent_expr: Option<&'tcx Expr<'tcx>>,
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 ff7769af1df..af90cb5e673 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -1,6 +1,6 @@
 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::ty::option_arg_ty;
 use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::ResultErr;
@@ -28,25 +28,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
         && is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr)
         && let Some(return_ty) = find_return_type(cx, &expr.kind)
     {
-        let prefix;
-        let suffix;
-        let err_ty;
-
-        if let Some(ty) = result_error_type(cx, return_ty) {
-            prefix = "Err(";
-            suffix = ")";
-            err_ty = ty;
+        let (prefix, suffix, err_ty) = if let Some(ty) = result_error_type(cx, return_ty) {
+            ("Err(", ")", ty)
         } else if let Some(ty) = poll_result_error_type(cx, return_ty) {
-            prefix = "Poll::Ready(Err(";
-            suffix = "))";
-            err_ty = ty;
+            ("Poll::Ready(Err(", "))", ty)
         } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) {
-            prefix = "Poll::Ready(Some(Err(";
-            suffix = ")))";
-            err_ty = ty;
+            ("Poll::Ready(Some(Err(", ")))", ty)
         } else {
             return;
-        }
+        };
 
         span_lint_and_then(
             cx,
@@ -88,8 +78,8 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O
 
 /// Extracts the error type from Result<T, E>.
 fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-    if let ty::Adt(_, subst) = ty.kind()
-        && is_type_diagnostic_item(cx, ty, sym::Result)
+    if let ty::Adt(def, subst) = ty.kind()
+        && cx.tcx.is_diagnostic_item(sym::Result, def.did())
     {
         Some(subst.type_at(1))
     } else {
@@ -101,11 +91,9 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
 fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if let ty::Adt(def, subst) = ty.kind()
         && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did())
-        && let ready_ty = subst.type_at(0)
-        && let ty::Adt(ready_def, ready_subst) = ready_ty.kind()
-        && cx.tcx.is_diagnostic_item(sym::Result, ready_def.did())
     {
-        Some(ready_subst.type_at(1))
+        let ready_ty = subst.type_at(0);
+        result_error_type(cx, ready_ty)
     } else {
         None
     }
@@ -116,13 +104,9 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) ->
     if let ty::Adt(def, subst) = ty.kind()
         && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did())
         && let ready_ty = subst.type_at(0)
-        && let ty::Adt(ready_def, ready_subst) = ready_ty.kind()
-        && cx.tcx.is_diagnostic_item(sym::Option, ready_def.did())
-        && let some_ty = ready_subst.type_at(0)
-        && let ty::Adt(some_def, some_subst) = some_ty.kind()
-        && cx.tcx.is_diagnostic_item(sym::Result, some_def.did())
+        && let Some(some_ty) = option_arg_ty(cx, ready_ty)
     {
-        Some(some_subst.type_at(1))
+        result_error_type(cx, some_ty)
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 28efd2038b3..e39916f733d 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -215,7 +215,8 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
         && let ExprKind::Path(ref repl_func_qpath) = repl_func.kind
         && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id()
     {
-        if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
+        let repl_name = cx.tcx.get_diagnostic_name(repl_def_id);
+        if repl_name == Some(sym::mem_uninitialized) {
             let Some(top_crate) = std_or_core(cx) else { return };
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
@@ -230,9 +231,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
                 ),
                 applicability,
             );
-        } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id)
-            && !cx.typeck_results().expr_ty(src).is_primitive()
-        {
+        } else if repl_name == Some(sym::mem_zeroed) && !cx.typeck_results().expr_ty(src).is_primitive() {
             span_lint_and_help(
                 cx,
                 MEM_REPLACE_WITH_UNINIT,
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 96e2de0dc1c..65583c6a981 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
@@ -24,9 +24,10 @@ pub(super) fn check(
         && let Some(name) = cx.tcx.get_diagnostic_name(adt.did())
     {
         let caller_type = match name {
-            sym::Rc => "Rc",
-            sym::Arc => "Arc",
-            sym::RcWeak | sym::ArcWeak => "Weak",
+            sym::Rc => "std::rc::Rc",
+            sym::Arc => "std::sync::Arc",
+            sym::RcWeak => "std::rc::Weak",
+            sym::ArcWeak => "std::sync::Weak",
             _ => return,
         };
         span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 5b8457bdd16..2da0f8341b1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -233,18 +233,16 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
             // the latter only calls `effect` once
             let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
 
-            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::is_some {
-                Some(Self::IsSome {
+            match (cx.tcx.get_diagnostic_name(recv_ty.did()), path.ident.name) {
+                (Some(sym::Option), sym::is_some) => Some(Self::IsSome {
                     receiver,
                     side_effect_expr_span,
-                })
-            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok {
-                Some(Self::IsOk {
+                }),
+                (Some(sym::Result), sym::is_ok) => Some(Self::IsOk {
                     receiver,
                     side_effect_expr_span,
-                })
-            } else {
-                None
+                }),
+                _ => None,
             }
         } else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some()
             // we know for a fact that the wildcard pattern is the second arm
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
index 9a62b719a8f..fa8f9d640ee 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
@@ -24,32 +24,29 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) ->
     let ty::Adt(adt, substs) = cx.typeck_results().expr_ty(iter).kind() else {
         return None;
     };
-    let did = adt.did();
 
-    if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) {
-        // For array::IntoIter<T, const N: usize>, the length is the second generic
-        // parameter.
-        substs.const_at(1).try_to_target_usize(cx.tcx).map(u128::from)
-    } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did)
-        && let ExprKind::MethodCall(_, recv, ..) = iter.kind
-    {
-        if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() {
-            // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..)
-            len.try_to_target_usize(cx.tcx).map(u128::from)
-        } else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) {
-            match args {
-                VecArgs::Vec(vec) => vec.len().try_into().ok(),
-                VecArgs::Repeat(_, len) => expr_as_u128(cx, len),
+    match cx.tcx.get_diagnostic_name(adt.did()) {
+        Some(sym::ArrayIntoIter) => {
+            // For array::IntoIter<T, const N: usize>, the length is the second generic
+            // parameter.
+            substs.const_at(1).try_to_target_usize(cx.tcx).map(u128::from)
+        },
+        Some(sym::SliceIter) if let ExprKind::MethodCall(_, recv, ..) = iter.kind => {
+            if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() {
+                // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..)
+                len.try_to_target_usize(cx.tcx).map(u128::from)
+            } else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) {
+                match args {
+                    VecArgs::Vec(vec) => vec.len().try_into().ok(),
+                    VecArgs::Repeat(_, len) => expr_as_u128(cx, len),
+                }
+            } else {
+                None
             }
-        } else {
-            None
-        }
-    } else if cx.tcx.is_diagnostic_item(sym::IterEmpty, did) {
-        Some(0)
-    } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) {
-        Some(1)
-    } else {
-        None
+        },
+        Some(sym::IterEmpty) => Some(0),
+        Some(sym::IterOnce) => Some(1),
+        _ => None,
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index f7bb8c1d696..750f933330a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -50,10 +50,10 @@ fn try_get_caller_ty_name_and_method_name(
         }
     } else {
         if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(caller_expr).kind() {
-            if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) {
-                return Some(("Option", "and_then"));
-            } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
-                return Some(("Result", "and_then"));
+            match cx.tcx.get_diagnostic_name(adt.did()) {
+                Some(sym::Option) => return Some(("Option", "and_then")),
+                Some(sym::Result) => return Some(("Result", "and_then")),
+                _ => {},
             }
         }
         None
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 98def66ca14..a98cfff8bfb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -1,14 +1,16 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expr_untyped_identity_function, is_trait_method, path_to_local};
-use rustc_ast::BindingMode;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::{is_expr_untyped_identity_function, is_mutable, is_trait_method, path_to_local_with_projections};
 use rustc_errors::Applicability;
-use rustc_hir::{self as hir, Node, PatKind};
-use rustc_lint::LateContext;
+use rustc_hir::{self as hir, ExprKind, Node, PatKind};
+use rustc_lint::{LateContext, LintContext};
 use rustc_span::{Span, Symbol, sym};
 
 use super::MAP_IDENTITY;
 
+const MSG: &str = "unnecessary map of the identity function";
+
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
@@ -23,26 +25,70 @@ pub(super) fn check(
         || is_type_diagnostic_item(cx, caller_ty, sym::Result)
         || is_type_diagnostic_item(cx, caller_ty, sym::Option))
         && is_expr_untyped_identity_function(cx, map_arg)
-        && let Some(sugg_span) = expr.span.trim_start(caller.span)
+        && let Some(call_span) = expr.span.trim_start(caller.span)
     {
-        // If the result of `.map(identity)` is used as a mutable reference,
-        // the caller must not be an immutable binding.
-        if cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr()
-            && let Some(hir_id) = path_to_local(caller)
-            && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
-            && !matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
-        {
-            return;
-        }
+        let main_sugg = (call_span, String::new());
+        let mut app = if is_copy(cx, caller_ty) {
+            // there is technically a behavioral change here for `Copy` iterators, where
+            // `iter.map(|x| x).next()` would mutate a temporary copy of the iterator and
+            // changing it to `iter.next()` mutates iter directly
+            Applicability::Unspecified
+        } else {
+            Applicability::MachineApplicable
+        };
+
+        let needs_to_be_mutable = cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr();
+        if needs_to_be_mutable && !is_mutable(cx, caller) {
+            if let Some(hir_id) = path_to_local_with_projections(caller)
+                && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
+                && let PatKind::Binding(_, _, ident, _) = pat.kind
+            {
+                // We can reach the binding -- suggest making it mutable
+                let suggs = vec![main_sugg, (ident.span.shrink_to_lo(), String::from("mut "))];
+
+                let ident = snippet_with_applicability(cx.sess(), ident.span, "_", &mut app);
 
-        span_lint_and_sugg(
-            cx,
-            MAP_IDENTITY,
-            sugg_span,
-            "unnecessary map of the identity function",
-            format!("remove the call to `{name}`"),
-            String::new(),
-            Applicability::MachineApplicable,
-        );
+                span_lint_and_then(cx, MAP_IDENTITY, call_span, MSG, |diag| {
+                    diag.multipart_suggestion(
+                        format!("remove the call to `{name}`, and make `{ident}` mutable"),
+                        suggs,
+                        app,
+                    );
+                });
+            } else {
+                // If we can't make the binding mutable, prevent the suggestion from being automatically applied,
+                // and add a complementary help message.
+                app = Applicability::Unspecified;
+
+                let method_requiring_mut = if let Node::Expr(expr) = cx.tcx.parent_hir_node(expr.hir_id)
+                    && let ExprKind::MethodCall(method, ..) = expr.kind
+                {
+                    Some(method.ident)
+                } else {
+                    None
+                };
+
+                span_lint_and_then(cx, MAP_IDENTITY, call_span, MSG, |diag| {
+                    diag.span_suggestion(main_sugg.0, format!("remove the call to `{name}`"), main_sugg.1, app);
+
+                    let note = if let Some(method_requiring_mut) = method_requiring_mut {
+                        format!("this must be made mutable to use `{method_requiring_mut}`")
+                    } else {
+                        "this must be made mutable".to_string()
+                    };
+                    diag.span_note(caller.span, note);
+                });
+            }
+        } else {
+            span_lint_and_sugg(
+                cx,
+                MAP_IDENTITY,
+                main_sugg.0,
+                MSG,
+                format!("remove the call to `{name}`"),
+                main_sugg.1,
+                app,
+            );
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 63ee922acfa..906ead16fd0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -38,17 +38,13 @@ pub(super) fn check(
     ];
 
     let is_deref = match map_arg.kind {
-        hir::ExprKind::Path(ref expr_qpath) => {
-            cx.qpath_res(expr_qpath, map_arg.hir_id)
-                .opt_def_id()
-                .is_some_and(|fun_def_id| {
-                    cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id)
-                        || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id)
-                        || deref_aliases
-                            .iter()
-                            .any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id))
-                })
-        },
+        hir::ExprKind::Path(ref expr_qpath) => cx
+            .qpath_res(expr_qpath, map_arg.hir_id)
+            .opt_def_id()
+            .and_then(|fun_def_id| cx.tcx.get_diagnostic_name(fun_def_id))
+            .is_some_and(|fun_name| {
+                matches!(fun_name, sym::deref_method | sym::deref_mut_method) || deref_aliases.contains(&fun_name)
+            }),
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let closure_body = cx.tcx.hir_body(body);
             let closure_expr = peel_blocks(closure_body.value);
@@ -63,13 +59,11 @@ pub(super) fn check(
                             .map(|x| &x.kind)
                             .collect::<Box<[_]>>()
                         && let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj
+                        && let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap()
+                        && let Some(method_name) = cx.tcx.get_diagnostic_name(method_did)
                     {
-                        let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
-                        cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
-                            || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did)
-                            || deref_aliases
-                                .iter()
-                                .any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did))
+                        matches!(method_name, sym::deref_method | sym::deref_mut_method)
+                            || deref_aliases.contains(&method_name)
                     } else {
                         false
                     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
index 3e64e15dc86..1a760ea733d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
@@ -62,7 +62,7 @@ fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: Lang
     if let ExprKind::Call(some_expr, [arg]) = expr.kind
         && is_res_lang_ctor(cx, path_res(cx, some_expr), item)
     {
-        Some(arg.span)
+        Some(arg.span.source_callsite())
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index 407f2e80aff..6738bbf0a12 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -31,8 +31,8 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
 }
 
 pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
-    if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
-        && cx.tcx.is_diagnostic_item(sym::Stdin, recv_adt.did())
+    let recv_ty = cx.typeck_results().expr_ty(recv);
+    if is_type_diagnostic_item(cx, recv_ty, sym::Stdin)
         && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
         && let Res::Local(local_id) = path.res
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
index ccdf5529d53..ef3d7acdc01 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
@@ -5,10 +5,10 @@ use rustc_span::sym;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
-        if cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) {
-            single_char_push_string::check(cx, expr, receiver, args);
-        } else if cx.tcx.is_diagnostic_item(sym::string_insert_str, fn_def_id) {
-            single_char_insert_string::check(cx, expr, receiver, args);
+        match cx.tcx.get_diagnostic_name(fn_def_id) {
+            Some(sym::string_push_str) => single_char_push_string::check(cx, expr, receiver, args),
+            Some(sym::string_insert_str) => single_char_insert_string::check(cx, expr, receiver, args),
+            _ => {},
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
index ce7aefed01f..ffc237e3c24 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
-use rustc_middle::ty::{self};
 use rustc_span::sym;
 
 use super::SUSPICIOUS_TO_OWNED;
@@ -14,8 +14,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -
     if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && is_diag_trait_item(cx, method_def_id, sym::ToOwned)
         && let input_type = cx.typeck_results().expr_ty(expr)
-        && let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind()
-        && cx.tcx.is_diagnostic_item(sym::Cow, adt.did())
+        && is_type_diagnostic_item(cx, input_type, sym::Cow)
     {
         let mut app = Applicability::MaybeIncorrect;
         let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
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 413881d5ec9..b87d81b7102 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
@@ -22,7 +22,8 @@ pub(super) fn check<'tcx>(
     let typeck_results = cx.typeck_results();
     let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck_results);
     if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id)
-        && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id))
+        && let Some(fn_name) = cx.tcx.get_diagnostic_name(id)
+        && matches!(fn_name, sym::cmp_ord_min | sym::cmp_ord_max)
     {
         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)
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 af466fe091c..af4ade3cc0f 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,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::{SpanRangeExt, snippet};
+use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::AdtDef;
 use rustc_span::{Span, sym};
 
 use crate::loops::UNUSED_ENUMERATE_INDEX;
@@ -39,9 +39,8 @@ use crate::loops::UNUSED_ENUMERATE_INDEX;
 /// * `closure_arg`: The argument to the map function call containing the closure/function to apply
 pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) {
     let recv_ty = cx.typeck_results().expr_ty(recv);
-    if let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did)
-        // If we call a method on a `std::iter::Enumerate` instance
-        && cx.tcx.is_diagnostic_item(sym::Enumerate, recv_ty_defid)
+    // If we call a method on a `std::iter::Enumerate` instance
+    if is_type_diagnostic_item(cx, recv_ty, sym::Enumerate)
         // If we are calling a method of the `Iterator` trait
         && is_trait_method(cx, call_expr, sym::Iterator)
         // And the map argument is a closure
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index d02952eb487..28555a61090 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_hir};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, Attribute, find_attr};
@@ -64,14 +64,20 @@ declare_clippy_lint! {
     "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)"
 }
 
-fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[Attribute], sp: Span, desc: &'static str) {
+fn check_missing_inline_attrs(
+    cx: &LateContext<'_>,
+    attrs: &[Attribute],
+    sp: Span,
+    desc: &'static str,
+    hir_id: Option<hir::HirId>,
+) {
     if !find_attr!(attrs, AttributeKind::Inline(..)) {
-        span_lint(
-            cx,
-            MISSING_INLINE_IN_PUBLIC_ITEMS,
-            sp,
-            format!("missing `#[inline]` for {desc}"),
-        );
+        let msg = format!("missing `#[inline]` for {desc}");
+        if let Some(hir_id) = hir_id {
+            span_lint_hir(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, hir_id, sp, msg);
+        } else {
+            span_lint(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, msg);
+        }
     }
 }
 
@@ -103,17 +109,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
 
                 let desc = "a function";
                 let attrs = cx.tcx.hir_attrs(it.hir_id());
-                check_missing_inline_attrs(cx, attrs, it.span, desc);
+                check_missing_inline_attrs(cx, attrs, it.span, desc, None);
             },
-            hir::ItemKind::Trait(
-                ref _constness,
-                ref _is_auto,
-                ref _unsafe,
-                _ident,
-                _generics,
-                _bounds,
-                trait_items,
-            ) => {
+            hir::ItemKind::Trait(.., trait_items) => {
                 // note: we need to check if the trait is exported so we can't use
                 // `LateLintPass::check_trait_item` here.
                 for &tit in trait_items {
@@ -127,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                                 let desc = "a default trait method";
                                 let item = cx.tcx.hir_trait_item(tit);
                                 let attrs = cx.tcx.hir_attrs(item.hir_id());
-                                check_missing_inline_attrs(cx, attrs, item.span, desc);
+                                check_missing_inline_attrs(cx, attrs, item.span, desc, Some(tit.hir_id()));
                             }
                         },
                     }
@@ -182,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
         }
 
         let attrs = cx.tcx.hir_attrs(impl_item.hir_id());
-        check_missing_inline_attrs(cx, attrs, impl_item.span, desc);
+        check_missing_inline_attrs(cx, attrs, impl_item.span, desc, None);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 31f51b45754..ec93ef97cfa 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -1,4 +1,6 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg::Sugg;
+use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
@@ -83,13 +85,18 @@ fn check_arguments<'tcx>(
         let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
         for (argument, parameter) in iter::zip(arguments, parameters) {
             if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind()
-                && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind
+                && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind
             {
-                span_lint(
+                let mut applicability = Applicability::MachineApplicable;
+                let sugg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability).addr();
+                span_lint_and_sugg(
                     cx,
                     UNNECESSARY_MUT_PASSED,
                     argument.span,
                     format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
+                    "remove this `mut`",
+                    sugg.to_string(),
+                    applicability,
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 6ae26156bc4..854e927aa2f 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -2,16 +2,14 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt,
-    is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_contains_comment, sym,
+    SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_parent_stmt, is_receiver_of_method_call,
+    peel_blocks, peel_blocks_with_stmt, span_contains_comment,
 };
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
-use rustc_span::source_map::Spanned;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -52,31 +50,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for expressions of the form `x == true`,
-    /// `x != true` and order comparisons such as `x < true` (or vice versa) and
-    /// suggest using the variable directly.
-    ///
-    /// ### Why is this bad?
-    /// Unnecessary code.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// if x == true {}
-    /// if y == false {}
-    /// ```
-    /// use `x` directly:
-    /// ```rust,ignore
-    /// if x {}
-    /// if !y {}
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub BOOL_COMPARISON,
-    complexity,
-    "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Checks for expressions of the form `if c { x = true } else { x = false }`
     /// (or vice versa) and suggest assigning the variable directly from the
     /// condition.
@@ -224,201 +197,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
     }
 }
 
-declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]);
-
-impl<'tcx> LateLintPass<'tcx> for BoolComparison {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if e.span.from_expansion() {
-            return;
-        }
-
-        if let ExprKind::Binary(Spanned { node, .. }, ..) = e.kind {
-            let ignore_case = None::<(fn(_) -> _, &str)>;
-            let ignore_no_literal = None::<(fn(_, _) -> _, &str)>;
-            match node {
-                BinOpKind::Eq => {
-                    let true_case = Some((|h| h, "equality checks against true are unnecessary"));
-                    let false_case = Some((
-                        |h: Sugg<'tcx>| !h,
-                        "equality checks against false can be replaced by a negation",
-                    ));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
-                },
-                BinOpKind::Ne => {
-                    let true_case = Some((
-                        |h: Sugg<'tcx>| !h,
-                        "inequality checks against true can be replaced by a negation",
-                    ));
-                    let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
-                },
-                BinOpKind::Lt => check_comparison(
-                    cx,
-                    e,
-                    ignore_case,
-                    Some((|h| h, "greater than checks against false are unnecessary")),
-                    Some((
-                        |h: Sugg<'tcx>| !h,
-                        "less than comparison against true can be replaced by a negation",
-                    )),
-                    ignore_case,
-                    Some((
-                        |l: Sugg<'tcx>, r: Sugg<'tcx>| (!l).bit_and(&r),
-                        "order comparisons between booleans can be simplified",
-                    )),
-                ),
-                BinOpKind::Gt => check_comparison(
-                    cx,
-                    e,
-                    Some((
-                        |h: Sugg<'tcx>| !h,
-                        "less than comparison against true can be replaced by a negation",
-                    )),
-                    ignore_case,
-                    ignore_case,
-                    Some((|h| h, "greater than checks against false are unnecessary")),
-                    Some((
-                        |l: Sugg<'tcx>, r: Sugg<'tcx>| l.bit_and(&(!r)),
-                        "order comparisons between booleans can be simplified",
-                    )),
-                ),
-                _ => (),
-            }
-        }
-    }
-}
-
-struct ExpressionInfoWithSpan {
-    one_side_is_unary_not: bool,
-    left_span: Span,
-    right_span: Span,
-}
-
-fn is_unary_not(e: &Expr<'_>) -> (bool, Span) {
-    if let ExprKind::Unary(UnOp::Not, operand) = e.kind {
-        return (true, operand.span);
-    }
-    (false, e.span)
-}
-
-fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr<'_>) -> ExpressionInfoWithSpan {
-    let left = is_unary_not(left_side);
-    let right = is_unary_not(right_side);
-
-    ExpressionInfoWithSpan {
-        one_side_is_unary_not: left.0 != right.0,
-        left_span: left.1,
-        right_span: right.1,
-    }
-}
-
-fn check_comparison<'a, 'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
-    left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
-    right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
-    right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
-    no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>,
-) {
-    if let ExprKind::Binary(op, left_side, right_side) = e.kind {
-        let (l_ty, r_ty) = (
-            cx.typeck_results().expr_ty(left_side),
-            cx.typeck_results().expr_ty(right_side),
-        );
-        if is_expn_of(left_side.span, sym::cfg).is_some() || is_expn_of(right_side.span, sym::cfg).is_some() {
-            return;
-        }
-        if l_ty.is_bool() && r_ty.is_bool() {
-            let mut applicability = Applicability::MachineApplicable;
-            // Eliminate parentheses in `e` by using the lo pos of lhs and hi pos of rhs,
-            // calling `source_callsite` make sure macros are handled correctly, see issue #9907
-            let binop_span = left_side
-                .span
-                .source_callsite()
-                .with_hi(right_side.span.source_callsite().hi());
-
-            if op.node == BinOpKind::Eq {
-                let expression_info = one_side_is_unary_not(left_side, right_side);
-                if expression_info.one_side_is_unary_not {
-                    span_lint_and_sugg(
-                        cx,
-                        BOOL_COMPARISON,
-                        binop_span,
-                        "this comparison might be written more concisely",
-                        "try simplifying it as shown",
-                        format!(
-                            "{} != {}",
-                            snippet_with_applicability(
-                                cx,
-                                expression_info.left_span.source_callsite(),
-                                "..",
-                                &mut applicability
-                            ),
-                            snippet_with_applicability(
-                                cx,
-                                expression_info.right_span.source_callsite(),
-                                "..",
-                                &mut applicability
-                            )
-                        ),
-                        applicability,
-                    );
-                }
-            }
-
-            match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
-                (Some(true), None) => left_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
-                }),
-                (None, Some(true)) => right_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
-                }),
-                (Some(false), None) => left_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
-                }),
-                (None, Some(false)) => right_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
-                }),
-                (None, None) => no_literal.map_or((), |(h, m)| {
-                    let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
-                    let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
-                    span_lint_and_sugg(
-                        cx,
-                        BOOL_COMPARISON,
-                        binop_span,
-                        m,
-                        "try simplifying it as shown",
-                        h(left_side, right_side).into_string(),
-                        applicability,
-                    );
-                }),
-                _ => (),
-            }
-        }
-    }
-}
-
-fn suggest_bool_comparison<'a, 'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    expr: &Expr<'_>,
-    mut app: Applicability,
-    message: &'static str,
-    conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
-) {
-    let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app);
-    span_lint_and_sugg(
-        cx,
-        BOOL_COMPARISON,
-        span,
-        message,
-        "try simplifying it as shown",
-        conv_hint(hint).into_string(),
-        app,
-    );
-}
-
 enum Expression {
     Bool(bool),
     RetBool(bool),
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index a67545e419c..3a6ccc2bca9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -1,6 +1,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
-use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind};
+use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
@@ -70,12 +70,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
             && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some()
             // Skip the lint if the body is not block because this is simpler than `for` loop.
             // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
-            && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind
+            && let ExprKind::Closure(&Closure { body, fn_decl, .. }) = for_each_arg.kind
             && let body = cx.tcx.hir_body(body)
             // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
             // and suggesting `for … in … { unsafe { } }` is a little ugly.
             && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..))
         {
+            let mut applicability = Applicability::MachineApplicable;
+
+            // If any closure parameter has an explicit type specified, applying the lint would necessarily
+            // remove that specification, possibly breaking type inference
+            if fn_decl
+                .inputs
+                .iter()
+                .any(|input| matches!(input.kind, TyKind::Infer(..)))
+            {
+                applicability = Applicability::MaybeIncorrect;
+            }
+
             let mut ret_collector = RetCollector::default();
             ret_collector.visit_expr(body.value);
 
@@ -84,18 +96,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
                 return;
             }
 
-            let (mut applicability, ret_suggs) = if ret_collector.spans.is_empty() {
-                (Applicability::MachineApplicable, None)
+            let ret_suggs = if ret_collector.spans.is_empty() {
+                None
             } else {
-                (
-                    Applicability::MaybeIncorrect,
-                    Some(
-                        ret_collector
-                            .spans
-                            .into_iter()
-                            .map(|span| (span, "continue".to_string()))
-                            .collect(),
-                    ),
+                applicability = Applicability::MaybeIncorrect;
+                Some(
+                    ret_collector
+                        .spans
+                        .into_iter()
+                        .map(|span| (span, "continue".to_string()))
+                        .collect(),
                 )
             };
 
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index 04b09276966..ba67dc62abb 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -134,7 +134,8 @@ impl LateLintPass<'_> for NonCanonicalImpls {
             return;
         }
 
-        if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id)
+        let trait_name = cx.tcx.get_diagnostic_name(trait_impl.def_id);
+        if trait_name == Some(sym::Clone)
             && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
             && implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[])
         {
@@ -170,12 +171,8 @@ impl LateLintPass<'_> for NonCanonicalImpls {
                     String::new(),
                     Applicability::MaybeIncorrect,
                 );
-
-                return;
             }
-        }
-
-        if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl.def_id)
+        } else if trait_name == Some(sym::PartialOrd)
             && impl_item.ident.name == sym::partial_cmp
             && let Some(ord_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
             && implements_trait(cx, trait_impl.self_ty(), ord_def_id, &[])
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index 23a1622f30f..cb934466bd8 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -43,13 +43,11 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
         match &expr.kind {
             ExprKind::MethodCall(path, func, [param], _) => {
                 if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def()
-                    && ((path.ident.name == sym::mode
-                        && matches!(
-                            cx.tcx.get_diagnostic_name(adt.did()),
-                            Some(sym::FsOpenOptions | sym::DirBuilder)
-                        ))
-                        || (path.ident.name == sym::set_mode
-                            && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
+                    && matches!(
+                        (cx.tcx.get_diagnostic_name(adt.did()), path.ident.name),
+                        (Some(sym::FsOpenOptions | sym::DirBuilder), sym::mode)
+                            | (Some(sym::FsPermissions), sym::set_mode)
+                    )
                     && let ExprKind::Lit(_) = param.kind
                     && param.span.eq_ctxt(expr.span)
                     && param
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 7317c62df7f..2d303e40bd1 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::qualify_min_const_fn::is_stable_const_fn;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::for_each_expr_without_closures;
@@ -20,7 +21,7 @@ pub(super) fn check<'tcx>(
     expr: &'tcx hir::Expr<'_>,
     assignee: &'tcx hir::Expr<'_>,
     e: &'tcx hir::Expr<'_>,
-    _msrv: Msrv,
+    msrv: Msrv,
 ) {
     if let hir::ExprKind::Binary(op, l, r) = &e.kind {
         let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
@@ -43,10 +44,28 @@ pub(super) fn check<'tcx>(
                     }
                 }
 
-                // Skip if the trait is not stable in const contexts
-                // FIXME: reintroduce a better check after this is merged back into Clippy
+                // Skip if the trait or the implementation is not stable in const contexts
                 if is_in_const_context(cx) {
-                    return;
+                    if cx
+                        .tcx
+                        .associated_item_def_ids(trait_id)
+                        .first()
+                        .is_none_or(|binop_id| !is_stable_const_fn(cx, *binop_id, msrv))
+                    {
+                        return;
+                    }
+
+                    let impls = cx.tcx.non_blanket_impls_for_ty(trait_id, rty).collect::<Vec<_>>();
+                    if impls.is_empty()
+                        || impls.into_iter().any(|impl_id| {
+                            cx.tcx
+                                .associated_item_def_ids(impl_id)
+                                .first()
+                                .is_none_or(|fn_id| !is_stable_const_fn(cx, *fn_id, msrv))
+                        })
+                    {
+                        return;
+                    }
                 }
 
                 span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index 22ec4fe60fb..604f8f5da0b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -47,14 +47,10 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
             (arg, arg.span)
         },
         ExprKind::Call(path, [arg])
-            if path_def_id(cx, path).is_some_and(|did| {
-                if cx.tcx.is_diagnostic_item(sym::from_str_method, did) {
-                    true
-                } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) {
-                    !is_copy(cx, typeck.expr_ty(expr))
-                } else {
-                    false
-                }
+            if path_def_id(cx, path).is_some_and(|did| match cx.tcx.get_diagnostic_name(did) {
+                Some(sym::from_str_method) => true,
+                Some(sym::from_fn) => !is_copy(cx, typeck.expr_ty(expr)),
+                _ => false,
             }) =>
         {
             (arg, arg.span)
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
index 047a5a0159c..17fa8017c97 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
@@ -34,10 +34,11 @@ pub(crate) fn check<'tcx>(
             val_r,
         ) = lhs.kind
 
-        // right hand side matches either f32::EPSILON or f64::EPSILON
+        // right hand side matches _::EPSILON
         && let ExprKind::Path(ref epsilon_path) = rhs.kind
         && let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id)
-        && ([sym::f32_epsilon, sym::f64_epsilon].into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, def_id)))
+        && let Some(sym) = cx.tcx.get_diagnostic_name(def_id)
+        && matches!(sym, sym::f16_epsilon | sym::f32_epsilon | sym::f64_epsilon | sym::f128_epsilon)
 
         // values of the subtractions on the left hand side are of the type float
         && let t_val_l = cx.typeck_results().expr_ty(val_l)
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index 449d3da7639..43db0085f2e 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_in_test;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
+use clippy_utils::{is_in_test, is_inside_always_const_context};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
@@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Some(macro_call) = root_macro_call_first_node(cx, expr) {
             if is_panic(cx, macro_call.def_id) {
-                if cx.tcx.hir_is_inside_const_context(expr.hir_id)
+                if is_inside_always_const_context(cx.tcx, expr.hir_id)
                     || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id)
                 {
                     return;
@@ -140,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
             && let Res::Def(DefKind::Fn, def_id) = expr_path.res
             && cx.tcx.is_diagnostic_item(sym::panic_any, def_id)
         {
-            if cx.tcx.hir_is_inside_const_context(expr.hir_id)
+            if is_inside_always_const_context(cx.tcx, expr.hir_id)
                 || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id)
             {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index e57b8cc2d84..1d58cdd26d8 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::fn_has_unsatisfiable_preds;
 use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, walk_ptrs_ty_depth};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, LangItem, def_id};
@@ -96,14 +96,13 @@ 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 fn_name = cx.tcx.get_diagnostic_name(fn_def_id);
+
             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));
+                || fn_name == Some(sym::to_owned_method)
+                || (fn_name == Some(sym::to_string_method) && is_type_lang_item(cx, arg_ty, LangItem::String));
 
-            let from_deref = !from_borrow
-                && (cx.tcx.is_diagnostic_item(sym::path_to_pathbuf, fn_def_id)
-                    || cx.tcx.is_diagnostic_item(sym::os_str_to_os_string, fn_def_id));
+            let from_deref = !from_borrow && matches!(fn_name, Some(sym::path_to_pathbuf | sym::os_str_to_os_string));
 
             if !from_borrow && !from_deref {
                 continue;
@@ -148,8 +147,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                     is_call_with_ref_arg(cx, mir, &pred_terminator.kind)
                     && res == cloned
                     && cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id)
-                    && (is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf)
-                        || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString))
+                    && let ty::Adt(pred_arg_def, _) = pred_arg_ty.kind()
+                    && let Some(pred_arg_name) = cx.tcx.get_diagnostic_name(pred_arg_def.did())
+                    && matches!(pred_arg_name, sym::PathBuf | sym::OsString)
                 {
                     (pred_arg, res)
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index db91c57b181..1dea8f17c34 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -155,6 +155,11 @@ impl LateLintPass<'_> for SemicolonBlock {
                 kind: ExprKind::Block(block, _),
                 ..
             }) if !block.span.from_expansion() => {
+                let attrs = cx.tcx.hir_attrs(stmt.hir_id);
+                if !attrs.is_empty() && !cx.tcx.features().stmt_expr_attributes() {
+                    return;
+                }
+
                 if let Some(tail) = block.expr {
                     self.semicolon_inside_block(cx, block, tail, stmt.span);
                 }
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 e9534bc63a6..8c4a50041e6 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
@@ -126,6 +126,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
             && !is_from_proc_macro(cx, &first_segment.ident)
             && !matches!(def_kind, DefKind::Macro(_))
             && let Some(last_segment) = path.segments.last()
+            && let Res::Def(DefKind::Mod, crate_def_id) = first_segment.res
+            && crate_def_id.is_crate_root()
         {
             let (lint, used_mod, replace_with) = match first_segment.ident.name {
                 sym::std => match cx.tcx.crate_name(def_id.krate) {
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 490e6c974ae..57d5900b045 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -457,7 +457,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
 }
 
 fn is_one_of_trim_diagnostic_items(cx: &LateContext<'_>, trim_def_id: DefId) -> bool {
-    cx.tcx.is_diagnostic_item(sym::str_trim, trim_def_id)
-        || cx.tcx.is_diagnostic_item(sym::str_trim_start, trim_def_id)
-        || cx.tcx.is_diagnostic_item(sym::str_trim_end, trim_def_id)
+    matches!(
+        cx.tcx.get_diagnostic_name(trim_def_id),
+        Some(sym::str_trim | sym::str_trim_start | sym::str_trim_end)
+    )
 }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
index 08f36a2ed5d..543f3c45e14 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -1,8 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use std::borrow::Cow;
+
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::{HasSession, SpanRangeExt as _};
 use rustc_errors::Applicability;
-use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind};
+use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::Span;
 
 use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS;
 
@@ -38,6 +42,7 @@ fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool {
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     path: &Path<'tcx>,
+    arg: &Expr<'tcx>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
     expr_hir_id: HirId,
@@ -68,14 +73,48 @@ pub(super) fn check<'tcx>(
     } else if is_function_block(cx, expr_hir_id) {
         return false;
     }
-    span_lint_and_sugg(
+    let span = last.ident.span.with_hi(path.span.hi());
+    span_lint_and_then(
         cx,
         MISSING_TRANSMUTE_ANNOTATIONS,
-        last.ident.span.with_hi(path.span.hi()),
+        span,
         "transmute used without annotations",
-        "consider adding missing annotations",
-        format!("{}::<{from_ty}, {to_ty}>", last.ident),
-        Applicability::MaybeIncorrect,
+        |diag| {
+            let from_ty_no_name = ty_cannot_be_named(from_ty);
+            let to_ty_no_name = ty_cannot_be_named(to_ty);
+            if from_ty_no_name || to_ty_no_name {
+                let to_name = match (from_ty_no_name, to_ty_no_name) {
+                    (true, false) => maybe_name_by_expr(cx, arg.span, "the origin type"),
+                    (false, true) => "the destination type".into(),
+                    _ => "the source and destination types".into(),
+                };
+                diag.help(format!(
+                    "consider giving {to_name} a name, and adding missing type annotations"
+                ));
+            } else {
+                diag.span_suggestion(
+                    span,
+                    "consider adding missing annotations",
+                    format!("{}::<{from_ty}, {to_ty}>", last.ident),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        },
     );
     true
 }
+
+fn ty_cannot_be_named(ty: Ty<'_>) -> bool {
+    matches!(
+        ty.kind(),
+        ty::Alias(ty::AliasTyKind::Opaque | ty::AliasTyKind::Inherent, _)
+    )
+}
+
+fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> {
+    span.with_source_text(sess, |name| {
+        (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into())
+    })
+    .flatten()
+    .unwrap_or(default.into())
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 1c7bb4314dd..5fda388259a 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -520,7 +520,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 | transmuting_null::check(cx, e, arg, to_ty)
                 | transmute_null_to_fn::check(cx, e, arg, to_ty)
                 | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
-                | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id)
+                | missing_transmute_annotations::check(cx, path, arg, from_ty, to_ty, e.hir_id)
                 | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv)
                 | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
index f27aaa2fa77..2257aa1b73c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
@@ -1,6 +1,6 @@
 use super::TRANSMUTE_INT_TO_NON_ZERO;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::sugg;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -16,35 +16,24 @@ pub(super) fn check<'tcx>(
     to_ty: Ty<'tcx>,
     arg: &'tcx Expr<'_>,
 ) -> bool {
-    let tcx = cx.tcx;
-
-    let (ty::Int(_) | ty::Uint(_), ty::Adt(adt, substs)) = (&from_ty.kind(), to_ty.kind()) else {
-        return false;
-    };
-
-    if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
-        return false;
+    if let ty::Int(_) | ty::Uint(_) = from_ty.kind()
+        && let ty::Adt(adt, substs) = to_ty.kind()
+        && cx.tcx.is_diagnostic_item(sym::NonZero, adt.did())
+        && let int_ty = substs.type_at(0)
+        && from_ty == int_ty
+    {
+        let arg = Sugg::hir(cx, arg, "..");
+        span_lint_and_sugg(
+            cx,
+            TRANSMUTE_INT_TO_NON_ZERO,
+            e.span,
+            format!("transmute from a `{from_ty}` to a `{}<{int_ty}>`", sym::NonZero),
+            "consider using",
+            format!("{}::{}({arg})", sym::NonZero, sym::new_unchecked),
+            Applicability::Unspecified,
+        );
+        true
+    } else {
+        false
     }
-
-    let int_ty = substs.type_at(0);
-    if from_ty != int_ty {
-        return false;
-    }
-
-    span_lint_and_then(
-        cx,
-        TRANSMUTE_INT_TO_NON_ZERO,
-        e.span,
-        format!("transmute from a `{from_ty}` to a `{}<{int_ty}>`", sym::NonZero),
-        |diag| {
-            let arg = sugg::Sugg::hir(cx, arg, "..");
-            diag.span_suggestion(
-                e.span,
-                "consider using",
-                format!("{}::{}({arg})", sym::NonZero, sym::new_unchecked),
-                Applicability::Unspecified,
-            );
-        },
-    );
-    true
 }
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 d691f1878b1..c4fd0fbf87a 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -11,7 +11,8 @@ use super::RC_BUFFER;
 
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
     let app = Applicability::Unspecified;
-    if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
+    let name = cx.tcx.get_diagnostic_name(def_id);
+    if name == Some(sym::Rc) {
         if let Some(alternate) = match_buffer_type(cx, qpath) {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
             span_lint_and_then(
@@ -56,7 +57,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             );
             return true;
         }
-    } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
+    } else if name == Some(sym::Arc) {
         if let Some(alternate) = match_buffer_type(cx, qpath) {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index de3456a8ba5..0ba51daf027 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -13,14 +13,11 @@ use super::{REDUNDANT_ALLOCATION, utils};
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: &QPath<'tcx>, def_id: DefId) -> bool {
     let mut applicability = Applicability::MaybeIncorrect;
-    let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
-        "Box"
-    } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
-        "Rc"
-    } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
-        "Arc"
-    } else {
-        return false;
+    let outer_sym = match cx.tcx.get_diagnostic_name(def_id) {
+        _ if Some(def_id) == cx.tcx.lang_items().owned_box() => "Box",
+        Some(sym::Rc) => "Rc",
+        Some(sym::Arc) => "Arc",
+        _ => return false,
     };
 
     if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index 48b532968cb..38716519e23 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
-use clippy_utils::sym;
+use clippy_utils::{is_unit_expr, sym};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 
@@ -16,10 +16,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 sym::assert_ne_macro | sym::debug_assert_ne_macro => "fail",
                 _ => return,
             };
-            let Some((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
+            let Some((lhs, rhs, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
                 return;
             };
-            if !cx.typeck_results().expr_ty(left).is_unit() {
+            if is_unit_expr(lhs) || is_unit_expr(rhs) {
+                return;
+            }
+            if !cx.typeck_results().expr_ty(lhs).is_unit() {
                 return;
             }
             span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
index 7d996775a58..28f4884fa31 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -41,7 +41,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
             && let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind()
             && inner_str.is_str()
         {
-            if cx.tcx.is_diagnostic_item(sym::string_new, fun_def_id) {
+            let fun_name = cx.tcx.get_diagnostic_name(fun_def_id);
+            if fun_name == Some(sym::string_new) {
                 span_lint_and_sugg(
                     cx,
                     UNNECESSARY_OWNED_EMPTY_STRINGS,
@@ -51,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
                     "\"\"".to_owned(),
                     Applicability::MachineApplicable,
                 );
-            } else if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id)
+            } else if fun_name == Some(sym::from_fn)
                 && let [arg] = args
                 && let ExprKind::Lit(spanned) = &arg.kind
                 && let LitKind::Str(symbol, _) = spanned.node
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 54a7efc090a..849c0b438a5 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -107,12 +107,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
         // Get the wrapper and inner types, if can't, abort.
         let (return_type_label, lang_item, inner_type) =
             if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id.expect_owner()).kind() {
-                if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
-                    ("Option", OptionSome, subst.type_at(0))
-                } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
-                    ("Result", ResultOk, subst.type_at(0))
-                } else {
-                    return;
+                match cx.tcx.get_diagnostic_name(adt_def.did()) {
+                    Some(sym::Option) => ("Option", OptionSome, subst.type_at(0)),
+                    Some(sym::Result) => ("Result", ResultOk, subst.type_at(0)),
+                    _ => return,
                 }
             } else {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 8b278d98a30..f3410c98973 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -326,7 +326,11 @@ fn extend_with_struct_pat(
                     if idx_1 == idx {
                         // In the case of `k`, we merely require identical field names
                         // so that we will transform into `ident_k: p1_k | p2_k`.
-                        let pos = fps2.iter().position(|fp2| eq_id(fp1.ident, fp2.ident));
+                        let pos = fps2.iter().position(|fp2| {
+                            // Avoid `Foo { bar } | Foo { bar }` => `Foo { bar | bar }`
+                            !(fp1.is_shorthand && fp2.is_shorthand)
+                                && eq_id(fp1.ident, fp2.ident)
+                        });
                         pos_in_2.set(pos);
                         pos.is_some()
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index f3cd3f1bb28..af3ad4566c4 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -89,7 +89,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
         {
             // We don't want to lint inside io::Read or io::Write implementations, as the author has more
             // information about their trait implementation than our lint, see https://github.com/rust-lang/rust-clippy/issues/4836
-            if cx.tcx.is_diagnostic_item(sym::IoRead, trait_id) || cx.tcx.is_diagnostic_item(sym::IoWrite, trait_id) {
+            if let Some(trait_name) = cx.tcx.get_diagnostic_name(trait_id)
+                && matches!(trait_name, sym::IoRead | sym::IoWrite)
+            {
                 return;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 3811f0fe6b5..d503bd3379b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -6,13 +6,13 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term,
-    Ty, TyKind,
+    AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, PolyTraitRef, Term, Ty,
+    TyKind,
 };
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::edition::Edition;
-use rustc_span::{BytePos, Span, sym};
+use rustc_span::{BytePos, Pos as _, Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -49,19 +49,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
         decl: &'tcx FnDecl<'tcx>,
         body: &'tcx Body<'tcx>,
         span: Span,
-        def_id: LocalDefId,
+        _def_id: LocalDefId,
     ) {
         if let FnRetTy::Return(hir_ty) = decl.output
             && is_unit_ty(hir_ty)
             && !hir_ty.span.from_expansion()
             && get_def(span) == get_def(hir_ty.span)
         {
-            // implicit types in closure signatures are forbidden when `for<...>` is present
-            if let FnKind::Closure = kind
-                && let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id)
-                && let ExprKind::Closure(closure) = expr.kind
-                && !closure.bound_generic_params.is_empty()
-            {
+            // The explicit `-> ()` in the closure signature might be necessary for multiple reasons:
+            // - Implicit types in closure signatures are forbidden when `for<...>` is present
+            // - If the closure body ends with a function call, and that function's return type is generic, the
+            //   `-> ()` could be required for it to be inferred
+            //
+            // There could be more reasons to have it, and, in general, we shouldn't discourage the users from
+            // writing more type annotations than strictly necessary, because it can help readability and
+            // maintainability
+            if let FnKind::Closure = kind {
                 return;
             }
 
@@ -97,16 +100,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
     }
 
     fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) {
-        let segments = &poly.trait_ref.path.segments;
-
-        if segments.len() == 1
-            && matches!(segments[0].ident.name, sym::Fn | sym::FnMut | sym::FnOnce)
-            && let Some(args) = segments[0].args
+        if let [segment] = &poly.trait_ref.path.segments
+            && matches!(segment.ident.name, sym::Fn | sym::FnMut | sym::FnOnce)
+            && let Some(args) = segment.args
             && args.parenthesized == GenericArgsParentheses::ParenSugar
-            && let constraints = &args.constraints
-            && constraints.len() == 1
-            && constraints[0].ident.name == sym::Output
-            && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind
+            && let [constraint] = &args.constraints
+            && constraint.ident.name == sym::Output
+            && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraint.kind
             && args.span_ext.hi() != poly.span.hi()
             && !hir_ty.span.from_expansion()
             && args.span_ext.hi() != hir_ty.span.hi()
@@ -160,17 +160,15 @@ fn get_def(span: Span) -> Option<Span> {
 
 fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) {
     let (ret_span, appl) =
-        span.with_hi(ty_span.hi())
-            .get_source_text(cx)
-            .map_or((ty_span, Applicability::MaybeIncorrect), |src| {
-                position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| {
-                    (
-                        #[expect(clippy::cast_possible_truncation)]
-                        ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)),
-                        Applicability::MachineApplicable,
-                    )
-                })
-            });
+        if let Some(Some(rpos)) = span.with_hi(ty_span.hi()).with_source_text(cx, position_before_rarrow) {
+            (
+                ty_span.with_lo(span.lo() + BytePos::from_usize(rpos)),
+                Applicability::MachineApplicable,
+            )
+        } else {
+            (ty_span, Applicability::MaybeIncorrect)
+        };
+
     span_lint_and_sugg(
         cx,
         UNUSED_UNIT,
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 7bec212a23c..f26647fa348 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{method_chain_args, return_ty};
-use core::ops::ControlFlow;
-use rustc_hir as hir;
-use rustc_hir::ImplItemKind;
+use clippy_utils::{return_ty, sym};
+use rustc_hir::{
+    Body, BodyOwnerKind, Expr, ExprKind, FnSig, ImplItem, ImplItemKind, Item, ItemKind, OwnerId, PathSegment, QPath,
+};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_middle::ty::Ty;
+use rustc_session::impl_lint_pass;
+use rustc_span::{Ident, Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -57,62 +56,165 @@ declare_clippy_lint! {
     "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`"
 }
 
-declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]);
+impl_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]);
 
-impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
-        if let ImplItemKind::Fn(ref _signature, _) = impl_item.kind
-            // first check if it's a method or function
-            // checking if its return type is `result` or `option`
-            && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
-                || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option))
-        {
-            lint_impl_body(cx, impl_item.span, impl_item);
+#[derive(Clone, Copy, Eq, PartialEq)]
+enum OptionOrResult {
+    Option,
+    Result,
+}
+
+impl OptionOrResult {
+    fn with_article(self) -> &'static str {
+        match self {
+            Self::Option => "an `Option`",
+            Self::Result => "a `Result`",
         }
     }
 }
 
-fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
-    if let ImplItemKind::Fn(_, body_id) = impl_item.kind {
-        let body = cx.tcx.hir_body(body_id);
-        let typeck = cx.tcx.typeck(impl_item.owner_id.def_id);
-        let mut result = Vec::new();
-        let _: Option<!> = for_each_expr(cx, body.value, |e| {
-            // check for `expect`
-            if let Some(arglists) = method_chain_args(e, &[sym::expect]) {
-                let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
-                if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
-                    || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
-                {
-                    result.push(e.span);
-                }
-            }
-
-            // check for `unwrap`
-            if let Some(arglists) = method_chain_args(e, &[sym::unwrap]) {
-                let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
-                if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
-                    || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
-                {
-                    result.push(e.span);
-                }
-            }
-
-            ControlFlow::Continue(())
+struct OptionOrResultFn {
+    kind: OptionOrResult,
+    return_ty_span: Option<Span>,
+}
+
+#[derive(Default)]
+pub struct UnwrapInResult {
+    fn_stack: Vec<Option<OptionOrResultFn>>,
+    current_fn: Option<OptionOrResultFn>,
+}
+
+impl UnwrapInResult {
+    fn enter_item(&mut self, cx: &LateContext<'_>, fn_def_id: OwnerId, sig: &FnSig<'_>) {
+        self.fn_stack.push(self.current_fn.take());
+        self.current_fn = is_option_or_result(cx, return_ty(cx, fn_def_id)).map(|kind| OptionOrResultFn {
+            kind,
+            return_ty_span: Some(sig.decl.output.span()),
         });
+    }
 
-        // if we've found one, lint
-        if !result.is_empty() {
+    fn leave_item(&mut self) {
+        self.current_fn = self.fn_stack.pop().unwrap();
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
+        if let ImplItemKind::Fn(sig, _) = &impl_item.kind {
+            self.enter_item(cx, impl_item.owner_id, sig);
+        }
+    }
+
+    fn check_impl_item_post(&mut self, _: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
+        if let ImplItemKind::Fn(..) = impl_item.kind {
+            self.leave_item();
+        }
+    }
+
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Fn {
+            has_body: true, sig, ..
+        } = &item.kind
+        {
+            self.enter_item(cx, item.owner_id, sig);
+        }
+    }
+
+    fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Fn { has_body: true, .. } = item.kind {
+            self.leave_item();
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        if let Some(OptionOrResultFn {
+            kind,
+            ref mut return_ty_span,
+        }) = self.current_fn
+            && let Some((oor, fn_name)) = is_unwrap_or_expect_call(cx, expr)
+            && oor == kind
+        {
             span_lint_and_then(
                 cx,
                 UNWRAP_IN_RESULT,
-                impl_span,
-                "used unwrap or expect in a function that returns result or option",
-                move |diag| {
-                    diag.help("unwrap and expect should not be used in a function that returns result or option");
-                    diag.span_note(result, "potential non-recoverable error(s)");
+                expr.span,
+                format!("`{fn_name}` used in a function that returns {}", kind.with_article()),
+                |diag| {
+                    // Issue the note and help only once per function
+                    if let Some(span) = return_ty_span.take() {
+                        diag.span_note(span, "in this function signature");
+                        let complement = if kind == OptionOrResult::Result {
+                            " or calling the `.map_err()` method"
+                        } else {
+                            ""
+                        };
+                        diag.help(format!("consider using the `?` operator{complement}"));
+                    }
                 },
             );
         }
     }
+
+    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
+        let body_def_id = cx.tcx.hir_body_owner_def_id(body.id());
+        if !matches!(cx.tcx.hir_body_owner_kind(body_def_id), BodyOwnerKind::Fn) {
+            // When entering a body which is not a function, mask the potential surrounding
+            // function to not apply the lint.
+            self.fn_stack.push(self.current_fn.take());
+        }
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
+        let body_def_id = cx.tcx.hir_body_owner_def_id(body.id());
+        if !matches!(cx.tcx.hir_body_owner_kind(body_def_id), BodyOwnerKind::Fn) {
+            // Unmask the potential surrounding function.
+            self.current_fn = self.fn_stack.pop().unwrap();
+        }
+    }
+}
+
+fn is_option_or_result(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<OptionOrResult> {
+    match ty.ty_adt_def().and_then(|def| cx.tcx.get_diagnostic_name(def.did())) {
+        Some(sym::Option) => Some(OptionOrResult::Option),
+        Some(sym::Result) => Some(OptionOrResult::Result),
+        _ => None,
+    }
+}
+
+fn is_unwrap_or_expect_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(OptionOrResult, Symbol)> {
+    if let ExprKind::Call(func, _) = expr.kind
+        && let ExprKind::Path(QPath::TypeRelative(
+            hir_ty,
+            PathSegment {
+                ident:
+                    Ident {
+                        name: name @ (sym::unwrap | sym::expect),
+                        ..
+                    },
+                ..
+            },
+        )) = func.kind
+    {
+        is_option_or_result(cx, cx.typeck_results().node_type(hir_ty.hir_id)).map(|oor| (oor, *name))
+    } else if let ExprKind::MethodCall(
+        PathSegment {
+            ident: Ident {
+                name: name @ (sym::unwrap | sym::expect),
+                ..
+            },
+            ..
+        },
+        recv,
+        _,
+        _,
+    ) = expr.kind
+    {
+        is_option_or_result(cx, cx.typeck_results().expr_ty_adjusted(recv)).map(|oor| (oor, *name))
+    } else {
+        None
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index e5b20c0e0a1..70ae982a445 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -386,12 +386,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
 
             ExprKind::Call(path, [arg]) => {
                 if let ExprKind::Path(ref qpath) = path.kind
-                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
                     && !is_ty_alias(qpath)
+                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                    && let Some(name) = cx.tcx.get_diagnostic_name(def_id)
                 {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(arg);
-                    if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id)
+                    if name == sym::try_from_fn
                         && is_type_diagnostic_item(cx, a, sym::Result)
                         && let ty::Adt(_, args) = a.kind()
                         && let Some(a_type) = args.types().next()
@@ -406,9 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             None,
                             hint,
                         );
-                    }
-
-                    if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) && same_type_and_consts(a, b) {
+                    } else if name == sym::from_fn && same_type_and_consts(a, b) {
                         let mut app = Applicability::MachineApplicable;
                         let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_paren();
                         let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 7b6a25123e8..52b30ddce12 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -1,4 +1,6 @@
 use std::collections::BTreeMap;
+use std::collections::btree_map::Entry;
+use std::mem;
 use std::ops::ControlFlow;
 
 use clippy_config::Conf;
@@ -20,15 +22,36 @@ use rustc_span::{DesugaringKind, Span};
 pub struct UselessVec {
     too_large_for_stack: u64,
     msrv: Msrv,
-    span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
+    /// Maps from a `vec![]` source callsite invocation span to the "state" (i.e., whether we can
+    /// emit a warning there or not).
+    ///
+    /// The purpose of this is to buffer lints up until `check_crate_post` so that we can cancel a
+    /// lint while visiting, because a `vec![]` invocation span can appear multiple times when
+    /// it is passed as a macro argument, once in a context that doesn't require a `Vec<_>` and
+    /// another time that does. Consider:
+    /// ```
+    /// macro_rules! m {
+    ///     ($v:expr) => {
+    ///         let a = $v;
+    ///         $v.push(3);
+    ///     }
+    /// }
+    /// m!(vec![1, 2]);
+    /// ```
+    /// The macro invocation expands to two `vec![1, 2]` invocations. If we eagerly suggest changing
+    /// the first `vec![1, 2]` (which is shared with the other expn) to an array which indeed would
+    /// work, we get a false positive warning on the `$v.push(3)` which really requires `$v` to
+    /// be a vector.
+    span_to_state: BTreeMap<Span, VecState>,
     allow_in_test: bool,
 }
+
 impl UselessVec {
     pub fn new(conf: &'static Conf) -> Self {
         Self {
             too_large_for_stack: conf.too_large_for_stack,
             msrv: conf.msrv,
-            span_to_lint_map: BTreeMap::new(),
+            span_to_state: BTreeMap::new(),
             allow_in_test: conf.allow_useless_vec_in_tests,
         }
     }
@@ -62,17 +85,28 @@ declare_clippy_lint! {
 
 impl_lint_pass!(UselessVec => [USELESS_VEC]);
 
-impl<'tcx> LateLintPass<'tcx> for UselessVec {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) else {
-            return;
-        };
-        if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) {
-            return;
-        }
-        // the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!`
-        let callsite = expr.span.parent_callsite().unwrap_or(expr.span);
+/// The "state" of a `vec![]` invocation, indicating whether it can or cannot be changed.
+enum VecState {
+    Change {
+        suggest_ty: SuggestedType,
+        vec_snippet: String,
+        expr_hir_id: HirId,
+    },
+    NoChange,
+}
+
+enum VecToArray {
+    /// Expression does not need to be a `Vec<_>` and its type can be changed to an array (or
+    /// slice).
+    Possible,
+    /// Expression must be a `Vec<_>`. Type cannot change.
+    Impossible,
+}
 
+impl UselessVec {
+    /// Checks if the surrounding environment requires this expression to actually be of type
+    /// `Vec<_>`, or if it can be changed to `&[]`/`[]` without causing type errors.
+    fn expr_usage_requires_vec(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) -> VecToArray {
         match cx.tcx.parent_hir_node(expr.hir_id) {
             // search for `let foo = vec![_]` expressions where all uses of `foo`
             // adjust to slices or call a method that exist on slices (e.g. len)
@@ -100,110 +134,126 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
                 .is_continue();
 
                 if only_slice_uses {
-                    self.check_vec_macro(cx, &vec_args, callsite, expr.hir_id, SuggestedType::Array);
+                    VecToArray::Possible
                 } else {
-                    self.span_to_lint_map.insert(callsite, None);
+                    VecToArray::Impossible
                 }
             },
             // if the local pattern has a specified type, do not lint.
             Node::LetStmt(LetStmt { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => {
-                self.span_to_lint_map.insert(callsite, None);
+                VecToArray::Impossible
             },
             // search for `for _ in vec![...]`
             Node::Expr(Expr { span, .. })
                 if span.is_desugaring(DesugaringKind::ForLoop) && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) =>
             {
-                let suggest_slice = suggest_type(expr);
-                self.check_vec_macro(cx, &vec_args, callsite, expr.hir_id, suggest_slice);
+                VecToArray::Possible
             },
             // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
             _ => {
-                let suggest_slice = suggest_type(expr);
-
                 if adjusts_to_slice(cx, expr) {
-                    self.check_vec_macro(cx, &vec_args, callsite, expr.hir_id, suggest_slice);
+                    VecToArray::Possible
                 } else {
-                    self.span_to_lint_map.insert(callsite, None);
+                    VecToArray::Impossible
                 }
             },
         }
     }
+}
+
+impl<'tcx> LateLintPass<'tcx> for UselessVec {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows())
+            // The `vec![]` or `&vec![]` invocation span.
+            && let vec_span = expr.span.parent_callsite().unwrap_or(expr.span)
+            && !vec_span.from_expansion()
+        {
+            if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) {
+                return;
+            }
+
+            match self.expr_usage_requires_vec(cx, expr) {
+                VecToArray::Possible => {
+                    let suggest_ty = suggest_type(expr);
+
+                    // Size and `Copy` checks don't depend on the enclosing usage of the expression
+                    // and don't need to be inserted into the state map.
+                    let vec_snippet = match vec_args {
+                        higher::VecArgs::Repeat(expr, len) => {
+                            if is_copy(cx, cx.typeck_results().expr_ty(expr))
+                                && let Some(Constant::Int(length)) = ConstEvalCtxt::new(cx).eval(len)
+                                && let Ok(length) = u64::try_from(length)
+                                && size_of(cx, expr)
+                                    .checked_mul(length)
+                                    .is_some_and(|size| size <= self.too_large_for_stack)
+                            {
+                                suggest_ty.snippet(
+                                    cx,
+                                    Some(expr.span.source_callsite()),
+                                    Some(len.span.source_callsite()),
+                                )
+                            } else {
+                                return;
+                            }
+                        },
+                        higher::VecArgs::Vec(args) => {
+                            if let Ok(length) = u64::try_from(args.len())
+                                && size_of(cx, expr)
+                                    .checked_mul(length)
+                                    .is_some_and(|size| size <= self.too_large_for_stack)
+                            {
+                                suggest_ty.snippet(
+                                    cx,
+                                    args.first().zip(args.last()).map(|(first, last)| {
+                                        first.span.source_callsite().to(last.span.source_callsite())
+                                    }),
+                                    None,
+                                )
+                            } else {
+                                return;
+                            }
+                        },
+                    };
+
+                    if let Entry::Vacant(entry) = self.span_to_state.entry(vec_span) {
+                        entry.insert(VecState::Change {
+                            suggest_ty,
+                            vec_snippet,
+                            expr_hir_id: expr.hir_id,
+                        });
+                    }
+                },
+                VecToArray::Impossible => {
+                    self.span_to_state.insert(vec_span, VecState::NoChange);
+                },
+            }
+        }
+    }
 
     fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
-        for (span, lint_opt) in &self.span_to_lint_map {
-            if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
-                let help_msg = format!("you can use {} directly", suggest_slice.desc());
-                span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| {
-                    // If the `vec!` macro contains comment, better not make the suggestion machine
-                    // applicable as it would remove them.
-                    let applicability = if *applicability != Applicability::Unspecified
-                        && let source_map = cx.tcx.sess.source_map()
-                        && span_contains_comment(source_map, *span)
-                    {
+        for (span, state) in mem::take(&mut self.span_to_state) {
+            if let VecState::Change {
+                suggest_ty,
+                vec_snippet,
+                expr_hir_id,
+            } = state
+            {
+                span_lint_hir_and_then(cx, USELESS_VEC, expr_hir_id, span, "useless use of `vec!`", |diag| {
+                    let help_msg = format!("you can use {} directly", suggest_ty.desc());
+                    // If the `vec!` macro contains comment, better not make the suggestion machine applicable as it
+                    // would remove them.
+                    let applicability = if span_contains_comment(cx.tcx.sess.source_map(), span) {
                         Applicability::Unspecified
                     } else {
-                        *applicability
+                        Applicability::MachineApplicable
                     };
-                    diag.span_suggestion(*span, help_msg, snippet, applicability);
+                    diag.span_suggestion(span, help_msg, vec_snippet, applicability);
                 });
             }
         }
     }
 }
 
-impl UselessVec {
-    fn check_vec_macro<'tcx>(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        vec_args: &higher::VecArgs<'tcx>,
-        span: Span,
-        hir_id: HirId,
-        suggest_slice: SuggestedType,
-    ) {
-        if span.from_expansion() {
-            return;
-        }
-
-        let snippet = match *vec_args {
-            higher::VecArgs::Repeat(elem, 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;
-                    }
-
-                    #[expect(clippy::cast_possible_truncation)]
-                    if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
-                        return;
-                    }
-
-                    suggest_slice.snippet(cx, Some(elem.span), Some(len.span))
-                } else {
-                    return;
-                }
-            },
-            higher::VecArgs::Vec(args) => {
-                let args_span = if let Some(last) = args.iter().last() {
-                    if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
-                        return;
-                    }
-                    Some(args[0].span.source_callsite().to(last.span.source_callsite()))
-                } else {
-                    None
-                };
-                suggest_slice.snippet(cx, args_span, None)
-            },
-        };
-
-        self.span_to_lint_map.entry(span).or_insert(Some((
-            hir_id,
-            suggest_slice,
-            snippet,
-            Applicability::MachineApplicable,
-        )));
-    }
-}
-
 #[derive(Copy, Clone)]
 pub(crate) enum SuggestedType {
     /// Suggest using a slice `&[..]` / `&mut [..]`
@@ -221,11 +271,17 @@ impl SuggestedType {
     }
 
     fn snippet(self, cx: &LateContext<'_>, args_span: Option<Span>, len_span: Option<Span>) -> String {
+        // Invariant of the lint as implemented: all spans are from the root context (and as a result,
+        // always trivially crate-local).
+        assert!(args_span.is_none_or(|s| !s.from_expansion()));
+        assert!(len_span.is_none_or(|s| !s.from_expansion()));
+
         let maybe_args = args_span
-            .and_then(|sp| sp.get_source_text(cx))
+            .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local"))
             .map_or(String::new(), |x| x.to_owned());
         let maybe_len = len_span
-            .and_then(|sp| sp.get_source_text(cx).map(|s| format!("; {s}")))
+            .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local"))
+            .map(|st| format!("; {st}"))
             .unwrap_or_default();
 
         match self {
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index a15e4e42e71..c55c5ec2f51 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -537,7 +537,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
 
             sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span));
 
-            if let Some((_, index)) = positional_arg_piece_span(piece) {
+            if let Some((_, index)) = format_arg_piece_span(piece) {
                 replaced_position.push(index);
             }
 
@@ -569,16 +569,11 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
     }
 }
 
-/// Extract Span and its index from the given `piece`, if it's positional argument.
-fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
+/// Extract Span and its index from the given `piece`
+fn format_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
     match piece {
         FormatArgsPiece::Placeholder(FormatPlaceholder {
-            argument:
-                FormatArgPosition {
-                    index: Ok(index),
-                    kind: FormatArgPositionKind::Number,
-                    ..
-                },
+            argument: FormatArgPosition { index: Ok(index), .. },
             span: Some(span),
             ..
         }) => Some((*span, *index)),
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index 6ab94a52210..a934d2094e0 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -1,5 +1,6 @@
 use ControlFlow::{Break, Continue};
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id};
 use rustc_ast::Mutability;
 use rustc_ast::visit::visit_opt;
@@ -58,8 +59,8 @@ declare_lint_pass!(ZombieProcesses => [ZOMBIE_PROCESSES]);
 impl<'tcx> LateLintPass<'tcx> for ZombieProcesses {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Call(..) | ExprKind::MethodCall(..) = expr.kind
-            && let Some(child_adt) = cx.typeck_results().expr_ty(expr).ty_adt_def()
-            && cx.tcx.is_diagnostic_item(sym::Child, child_adt.did())
+            && let child_ty = cx.typeck_results().expr_ty(expr)
+            && is_type_diagnostic_item(cx, child_ty, sym::Child)
         {
             match cx.tcx.parent_hir_node(expr.hir_id) {
                 Node::LetStmt(local)
@@ -177,8 +178,8 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
                 Node::Expr(expr) if let ExprKind::AddrOf(_, Mutability::Not, _) = expr.kind => {},
                 Node::Expr(expr)
                     if let Some(fn_did) = fn_def_id(self.cx, expr)
-                        && (self.cx.tcx.is_diagnostic_item(sym::child_id, fn_did)
-                            || self.cx.tcx.is_diagnostic_item(sym::child_kill, fn_did)) => {},
+                        && let Some(fn_name) = self.cx.tcx.get_diagnostic_name(fn_did)
+                        && matches!(fn_name, sym::child_id | sym::child_kill) => {},
 
                 // Conservatively assume that all other kinds of nodes call `.wait()` somehow.
                 _ => return Break(MaybeWait(ex.span)),
@@ -351,9 +352,14 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Caus
 
 /// Checks if the given expression exits the process.
 fn is_exit_expression(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    fn_def_id(cx, expr).is_some_and(|fn_did| {
-        cx.tcx.is_diagnostic_item(sym::process_exit, fn_did) || cx.tcx.is_diagnostic_item(sym::process_abort, fn_did)
-    })
+    if let Some(fn_did) = fn_def_id(cx, expr)
+        && let Some(fn_name) = cx.tcx.get_diagnostic_name(fn_did)
+        && matches!(fn_name, sym::process_exit | sym::process_abort)
+    {
+        true
+    } else {
+        false
+    }
 }
 
 #[derive(Debug)]
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 2dfe28953d0..e01f563c49e 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-08-22
+nightly-2025-09-04
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index 40c00568a3b..ad69e6eb184 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -21,7 +21,7 @@ pub fn is_useless_with_eq_exprs(kind: BinOpKind) -> bool {
 }
 
 /// Checks if each element in the first slice is contained within the latter as per `eq_fn`.
-pub fn unordered_over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
+pub fn unordered_over<X, Y>(left: &[X], right: &[Y], mut eq_fn: impl FnMut(&X, &Y) -> bool) -> bool {
     left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r)))
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 4e0b00df950..bda28a663fb 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -287,23 +287,22 @@ impl<'a> VecArgs<'a> {
             && let ExprKind::Path(ref qpath) = fun.kind
             && is_expn_of(fun.span, sym::vec).is_some()
             && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
+            && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id)
         {
-            return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 {
-                // `vec![elem; size]` case
-                Some(VecArgs::Repeat(&args[0], &args[1]))
-            } else if cx.tcx.is_diagnostic_item(sym::slice_into_vec, fun_def_id) && args.len() == 1 {
-                // `vec![a, b, c]` case
-                if let ExprKind::Call(_, [arg]) = &args[0].kind
-                    && let ExprKind::Array(args) = arg.kind
+            return match (name, args) {
+                (sym::vec_from_elem, [elem, size]) => {
+                    // `vec![elem; size]` case
+                    Some(VecArgs::Repeat(elem, size))
+                },
+                (sym::slice_into_vec, [slice])
+                    if let ExprKind::Call(_, [arg]) = slice.kind
+                        && let ExprKind::Array(args) = arg.kind =>
                 {
+                    // `vec![a, b, c]` case
                     Some(VecArgs::Vec(args))
-                } else {
-                    None
-                }
-            } else if cx.tcx.is_diagnostic_item(sym::vec_new, fun_def_id) && args.is_empty() {
-                Some(VecArgs::Vec(&[]))
-            } else {
-                None
+                },
+                (sym::vec_new, []) => Some(VecArgs::Vec(&[])),
+                _ => None,
             };
         }
 
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 8160443f413..b79e15cd717 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -757,7 +757,7 @@ pub fn both_some_and<X, Y>(l: Option<X>, r: Option<Y>, mut pred: impl FnMut(X, Y
 }
 
 /// Checks if two slices are equal as per `eq_fn`.
-pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
+pub fn over<X, Y>(left: &[X], right: &[Y], mut eq_fn: impl FnMut(&X, &Y) -> bool) -> bool {
     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 011c9b2f931..14b64eb4d54 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -102,9 +102,9 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
 use rustc_hir::{
     self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, CoroutineDesugaring,
-    CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl,
-    ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
-    Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem,
+    CoroutineKind, CoroutineSource, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs,
+    HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId,
+    OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem,
     TraitItemKind, TraitRef, TyKind, UnOp, def, find_attr,
 };
 use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
@@ -126,6 +126,7 @@ use rustc_span::{InnerSpan, Span};
 use source::{SpanRangeExt, walk_span_to_context};
 use visitors::{Visitable, for_each_unconsumed_temporary};
 
+use crate::ast_utils::unordered_over;
 use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
 use crate::higher::Range;
 use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
@@ -308,6 +309,7 @@ pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) ->
     cx.tcx.lang_items().get(item) == Some(did)
 }
 
+/// Checks if `expr` is an empty block or an empty tuple.
 pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
     matches!(
         expr.kind,
@@ -640,9 +642,8 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
         && let Some(impl_did) = cx.tcx.impl_of_assoc(def_id)
         && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
     {
-        return std_types_symbols.iter().any(|&symbol| {
-            cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
-        });
+        return Some(adt.did()) == cx.tcx.lang_items().string()
+            || (cx.tcx.get_diagnostic_name(adt.did())).is_some_and(|adt_name| std_types_symbols.contains(&adt_name));
     }
     false
 }
@@ -1992,7 +1993,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
         (PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup))
             if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() =>
         {
-            zip(pats, tup).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr, by_hir))
+            over(pats, tup, |pat, expr| is_expr_identity_of_pat(cx, pat, expr, by_hir))
         },
         (PatKind::Slice(before, None, after), ExprKind::Array(arr)) if before.len() + after.len() == arr.len() => {
             zip(before.iter().chain(after), arr).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr, by_hir))
@@ -2004,7 +2005,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
             if let ExprKind::Path(ident) = &ident.kind
                 && qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id)
                 // check fields
-                && zip(field_pats, fields).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr,by_hir))
+                && over(field_pats, fields, |pat, expr| is_expr_identity_of_pat(cx, pat, expr,by_hir))
             {
                 true
             } else {
@@ -2017,10 +2018,8 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
             // check ident
             qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id)
                 // check fields
-                && field_pats.iter().all(|field_pat| {
-                    fields.iter().any(|field| {
-                        field_pat.ident == field.ident && is_expr_identity_of_pat(cx, field_pat.pat, field.expr, by_hir)
-                    })
+                && unordered_over(field_pats, fields, |field_pat, field| {
+                    field_pat.ident == field.ident && is_expr_identity_of_pat(cx, field_pat.pat, field.expr, by_hir)
                 })
         },
         _ => false,
@@ -2405,6 +2404,24 @@ pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>
     expr
 }
 
+/// Returns a `Vec` of `Expr`s containing `AddrOf` operators (`&`) or deref operators (`*`) of a
+/// given expression.
+pub fn get_ref_operators<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Vec<&'hir Expr<'hir>> {
+    let mut operators = Vec::new();
+    peel_hir_expr_while(expr, |expr| match expr.kind {
+        ExprKind::AddrOf(_, _, e) => {
+            operators.push(expr);
+            Some(e)
+        },
+        ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => {
+            operators.push(expr);
+            Some(e)
+        },
+        _ => None,
+    });
+    operators
+}
+
 pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
     if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
         && let Res::Def(_, def_id) = path.res
@@ -3633,3 +3650,17 @@ pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>)
         )
     })
 }
+
+/// Checks if the expression is an async block (i.e., `async { ... }`).
+pub fn is_expr_async_block(expr: &Expr<'_>) -> bool {
+    matches!(
+        expr.kind,
+        ExprKind::Closure(Closure {
+            kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(
+                CoroutineDesugaring::Async,
+                CoroutineSource::Block
+            )),
+            ..
+        })
+    )
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index fafc1d07e51..8e302f9d2ad 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -387,10 +387,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
 /// Checks if the type is a reference equals to a diagnostic item
 pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
     match ty.kind() {
-        ty::Ref(_, ref_ty, _) => match ref_ty.kind() {
-            ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()),
-            _ => false,
-        },
+        ty::Ref(_, ref_ty, _) => is_type_diagnostic_item(cx, *ref_ty, diag_item),
         _ => false,
     }
 }
@@ -1378,9 +1375,7 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'
 
 /// Check if `ty` is slice-like, i.e., `&[T]`, `[T; N]`, or `Vec<T>`.
 pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    ty.is_slice()
-        || ty.is_array()
-        || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did()))
+    ty.is_slice() || ty.is_array() || is_type_diagnostic_item(cx, ty, sym::Vec)
 }
 
 pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> {
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 76d43feee12..6eccbcdb122 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -144,11 +144,9 @@ impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> {
 
 /// Checks if the given expression is a macro call to `todo!()` or `unimplemented!()`.
 pub fn is_todo_unimplemented_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    root_macro_call_first_node(cx, expr).is_some_and(|macro_call| {
-        [sym::todo_macro, sym::unimplemented_macro]
-            .iter()
-            .any(|&sym| cx.tcx.is_diagnostic_item(sym, macro_call.def_id))
-    })
+    root_macro_call_first_node(cx, expr)
+        .and_then(|macro_call| cx.tcx.get_diagnostic_name(macro_call.def_id))
+        .is_some_and(|macro_name| matches!(macro_name, sym::todo_macro | sym::unimplemented_macro))
 }
 
 /// Checks if the given expression is a stub, i.e., a `todo!()` or `unimplemented!()` expression,
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index 5497e77e8ad..ec2f24a0a6d 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-08-22"
+channel = "nightly-2025-09-04"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index c4076cbaa77..6bddcbfd94c 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -330,7 +330,8 @@ pub fn main() {
 
         // Do not run Clippy for Cargo's info queries so that invalid CLIPPY_ARGS are not cached
         // https://github.com/rust-lang/cargo/issues/14385
-        let info_query = has_arg(&orig_args, "-vV") || has_arg(&orig_args, "--print");
+        let info_query = has_arg(&orig_args, "-vV")
+            || arg_value(&orig_args, "--print", |val| val != "crate-root-lint-levels").is_some();
 
         let clippy_enabled = !cap_lints_allow && relevant_package && !info_query;
         if clippy_enabled {
diff --git a/src/tools/clippy/tests/config-consistency.rs b/src/tools/clippy/tests/config-consistency.rs
new file mode 100644
index 00000000000..9e7ca26c7d4
--- /dev/null
+++ b/src/tools/clippy/tests/config-consistency.rs
@@ -0,0 +1,30 @@
+#![feature(rustc_private)]
+
+// This test checks that all lints defined in `clippy_config::conf` in `#[lints]`
+// attributes exist as Clippy lints.
+//
+// This test is a no-op if run as part of the compiler test suite
+// and will always succeed.
+
+use std::collections::HashSet;
+
+#[test]
+fn config_consistency() {
+    if option_env!("RUSTC_TEST_SUITE").is_some() {
+        return;
+    }
+
+    let lint_names: HashSet<String> = clippy_lints::declared_lints::LINTS
+        .iter()
+        .map(|lint_info| lint_info.lint.name.strip_prefix("clippy::").unwrap().to_lowercase())
+        .collect();
+    for conf in clippy_config::get_configuration_metadata() {
+        for lint in conf.lints {
+            assert!(
+                lint_names.contains(*lint),
+                "Configuration option {} references lint `{lint}` which does not exist",
+                conf.name
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/no-profile-in-cargo-toml.rs b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
new file mode 100644
index 00000000000..2ad9bfb75de
--- /dev/null
+++ b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
@@ -0,0 +1,34 @@
+// Check that we do not have `profile.*` sections in our `Cargo.toml` files,
+// as this causes warnings when run from the compiler repository which includes
+// Clippy in a workspace.
+//
+// Those sections can be put into `.cargo/config.toml` which will be read
+// when commands are issued from the top-level Clippy directory, outside of
+// a workspace.
+
+use std::fs::File;
+use std::io::{self, BufRead as _};
+use walkdir::WalkDir;
+
+#[test]
+fn no_profile_in_cargo_toml() {
+    // This check could parse `Cargo.toml` using a TOML deserializer, but in practice
+    // profile sections would be added at the beginning of a line as `[profile.*]`, so
+    // keep it fast and simple.
+    for entry in WalkDir::new(".")
+        .into_iter()
+        .filter_map(Result::ok)
+        .filter(|e| e.file_name().to_str() == Some("Cargo.toml"))
+    {
+        for line in io::BufReader::new(File::open(entry.path()).unwrap())
+            .lines()
+            .map(Result::unwrap)
+        {
+            if line.starts_with("[profile.") {
+                eprintln!("Profile section `{line}` found in file `{}`.", entry.path().display());
+                eprintln!("Use `.cargo/config.toml` for profiles specific to the standalone Clippy repository.");
+                panic!("Profile section found in `Cargo.toml`");
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
index f03a745963e..e9d53c64dd9 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
@@ -4,7 +4,7 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
 LL |     cx.span_lint(lint, span, |lint| {
    |        ^^^^^^^^^
    |
-   = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead
+   = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead
 note: the lint level is defined here
   --> tests/ui-internal/disallow_span_lint.rs:2:9
    |
@@ -17,7 +17,7 @@ error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_
 LL |     tcx.node_span_lint(lint, hir_id, span, |lint| {
    |         ^^^^^^^^^^^^^^
    |
-   = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead
+   = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/clippy.toml b/src/tools/clippy/tests/ui-toml/excessive_precision/clippy.toml
new file mode 100644
index 00000000000..c7fc230dcb3
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/excessive_precision/clippy.toml
@@ -0,0 +1 @@
+const-literal-digits-threshold = 20
diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.fixed b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.fixed
new file mode 100644
index 00000000000..577bbff2957
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.fixed
@@ -0,0 +1,38 @@
+#![warn(clippy::excessive_precision)]
+#![allow(
+    dead_code,
+    overflowing_literals,
+    unused_variables,
+    clippy::print_literal,
+    clippy::useless_vec
+)]
+
+fn main() {
+    // Overly specified constants
+    let _: f32 = 1.012_345_7;
+    //~^ excessive_precision
+    let _: f64 = 1.012_345_678_901_234_6;
+    //~^ excessive_precision
+    const _: f32 = 1.012345678901234567890;
+    const _: f64 = 1.012345678901234567890;
+
+    static STATIC1: f32 = 1.012345678901234567890;
+    static STATIC2: f64 = 1.012345678901234567890;
+
+    static mut STATIC_MUT1: f32 = 1.012345678901234567890;
+    static mut STATIC_MUT2: f64 = 1.012345678901234567890;
+}
+
+trait ExcessivelyPreciseTrait {
+    // Overly specified constants
+    const GOOD1: f32 = 1.012345678901234567890;
+    const GOOD2: f64 = 1.012345678901234567890;
+}
+
+struct ExcessivelyPreciseStruct;
+
+impl ExcessivelyPreciseStruct {
+    // Overly specified constants
+    const GOOD1: f32 = 1.012345678901234567890;
+    const GOOD2: f64 = 1.012345678901234567890;
+}
diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.rs b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.rs
new file mode 100644
index 00000000000..121448ed540
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.rs
@@ -0,0 +1,38 @@
+#![warn(clippy::excessive_precision)]
+#![allow(
+    dead_code,
+    overflowing_literals,
+    unused_variables,
+    clippy::print_literal,
+    clippy::useless_vec
+)]
+
+fn main() {
+    // Overly specified constants
+    let _: f32 = 1.012345678901234567890;
+    //~^ excessive_precision
+    let _: f64 = 1.012345678901234567890;
+    //~^ excessive_precision
+    const _: f32 = 1.012345678901234567890;
+    const _: f64 = 1.012345678901234567890;
+
+    static STATIC1: f32 = 1.012345678901234567890;
+    static STATIC2: f64 = 1.012345678901234567890;
+
+    static mut STATIC_MUT1: f32 = 1.012345678901234567890;
+    static mut STATIC_MUT2: f64 = 1.012345678901234567890;
+}
+
+trait ExcessivelyPreciseTrait {
+    // Overly specified constants
+    const GOOD1: f32 = 1.012345678901234567890;
+    const GOOD2: f64 = 1.012345678901234567890;
+}
+
+struct ExcessivelyPreciseStruct;
+
+impl ExcessivelyPreciseStruct {
+    // Overly specified constants
+    const GOOD1: f32 = 1.012345678901234567890;
+    const GOOD2: f64 = 1.012345678901234567890;
+}
diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.stderr b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.stderr
new file mode 100644
index 00000000000..65d33eddef1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.stderr
@@ -0,0 +1,38 @@
+error: float has excessive precision
+  --> tests/ui-toml/excessive_precision/excessive_precision.rs:12:18
+   |
+LL |     let _: f32 = 1.012345678901234567890;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider making it a `const` item
+  --> tests/ui-toml/excessive_precision/excessive_precision.rs:12:5
+   |
+LL |     let _: f32 = 1.012345678901234567890;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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 -     let _: f32 = 1.012345678901234567890;
+LL +     let _: f32 = 1.012_345_7;
+   |
+
+error: float has excessive precision
+  --> tests/ui-toml/excessive_precision/excessive_precision.rs:14:18
+   |
+LL |     let _: f64 = 1.012345678901234567890;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider making it a `const` item
+  --> tests/ui-toml/excessive_precision/excessive_precision.rs:14:5
+   |
+LL |     let _: f64 = 1.012345678901234567890;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the type or truncating it to
+   |
+LL -     let _: f64 = 1.012345678901234567890;
+LL +     let _: f64 = 1.012_345_678_901_234_6;
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 6ee77ebd8ec..20aeb4bb849 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -35,6 +35,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            check-inconsistent-struct-field-initializers
            check-private-items
            cognitive-complexity-threshold
+           const-literal-digits-threshold
            disallowed-macros
            disallowed-methods
            disallowed-names
@@ -129,6 +130,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            check-inconsistent-struct-field-initializers
            check-private-items
            cognitive-complexity-threshold
+           const-literal-digits-threshold
            disallowed-macros
            disallowed-methods
            disallowed-names
@@ -223,6 +225,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            check-inconsistent-struct-field-initializers
            check-private-items
            cognitive-complexity-threshold
+           const-literal-digits-threshold
            disallowed-macros
            disallowed-methods
            disallowed-names
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
index 09c1a8d0ed1..b2b7318c113 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
@@ -82,9 +82,18 @@ fn main() {
     assert!(r.is_err());
 }
 
-#[allow(dead_code)]
 fn issue9450() {
     let res: Result<i32, i32> = Ok(1);
     res.unwrap_err();
     //~^ assertions_on_result_states
 }
+
+fn issue9916(res: Result<u32, u32>) {
+    let a = 0;
+    match a {
+        0 => {},
+        1 => { res.unwrap(); },
+        //~^ assertions_on_result_states
+        _ => todo!(),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs
index c63c2502b53..33f1485326b 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.rs
@@ -82,9 +82,18 @@ fn main() {
     assert!(r.is_err());
 }
 
-#[allow(dead_code)]
 fn issue9450() {
     let res: Result<i32, i32> = Ok(1);
     assert!(res.is_err())
     //~^ assertions_on_result_states
 }
+
+fn issue9916(res: Result<u32, u32>) {
+    let a = 0;
+    match a {
+        0 => {},
+        1 => assert!(res.is_ok()),
+        //~^ assertions_on_result_states
+        _ => todo!(),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
index 3bf811588c6..826f049555c 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
@@ -38,10 +38,16 @@ LL |     assert!(r.is_err());
    |     ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()`
 
 error: called `assert!` with `Result::is_err`
-  --> tests/ui/assertions_on_result_states.rs:88:5
+  --> tests/ui/assertions_on_result_states.rs:87:5
    |
 LL |     assert!(res.is_err())
    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with: `res.unwrap_err();`
 
-error: aborting due to 7 previous errors
+error: called `assert!` with `Result::is_ok`
+  --> tests/ui/assertions_on_result_states.rs:95:14
+   |
+LL |         1 => assert!(res.is_ok()),
+   |              ^^^^^^^^^^^^^^^^^^^^ help: replace with: `{ res.unwrap(); }`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
index 3754b9dfe74..2046d089d6a 100644
--- a/src/tools/clippy/tests/ui/assign_ops.fixed
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -1,8 +1,9 @@
 #![allow(clippy::useless_vec)]
 #![warn(clippy::assign_op_pattern)]
-#![feature(const_trait_impl, const_ops)]
+#![feature(const_ops)]
+#![feature(const_trait_impl)]
 
-use core::num::Wrapping;
+use std::num::Wrapping;
 use std::ops::{Mul, MulAssign};
 
 fn main() {
@@ -82,6 +83,18 @@ mod issue14871 {
     pub trait Number: Copy + Add<Self, Output = Self> + AddAssign {
         const ZERO: Self;
         const ONE: Self;
+
+        fn non_constant(value: usize) -> Self {
+            let mut res = Self::ZERO;
+            let mut count = 0;
+            while count < value {
+                res += Self::ONE;
+                //~^ assign_op_pattern
+                count += 1;
+                //~^ assign_op_pattern
+            }
+            res
+        }
     }
 
     #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet)
@@ -91,7 +104,7 @@ mod issue14871 {
 
     impl<T> const NumberConstants for T
     where
-        T: Number + [const] core::ops::Add,
+        T: Number + [const] std::ops::Add,
     {
         fn constant(value: usize) -> Self {
             let mut res = Self::ZERO;
@@ -99,8 +112,28 @@ mod issue14871 {
             while count < value {
                 res = res + Self::ONE;
                 count += 1;
+                //~^ assign_op_pattern
             }
             res
         }
     }
+
+    pub struct S;
+
+    impl const std::ops::Add for S {
+        type Output = S;
+        fn add(self, _rhs: S) -> S {
+            S
+        }
+    }
+
+    impl const std::ops::AddAssign for S {
+        fn add_assign(&mut self, rhs: S) {}
+    }
+
+    const fn do_add() {
+        let mut s = S;
+        s += S;
+        //~^ assign_op_pattern
+    }
 }
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
index 0b878d4f490..f83a40f5547 100644
--- a/src/tools/clippy/tests/ui/assign_ops.rs
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -1,8 +1,9 @@
 #![allow(clippy::useless_vec)]
 #![warn(clippy::assign_op_pattern)]
-#![feature(const_trait_impl, const_ops)]
+#![feature(const_ops)]
+#![feature(const_trait_impl)]
 
-use core::num::Wrapping;
+use std::num::Wrapping;
 use std::ops::{Mul, MulAssign};
 
 fn main() {
@@ -82,6 +83,18 @@ mod issue14871 {
     pub trait Number: Copy + Add<Self, Output = Self> + AddAssign {
         const ZERO: Self;
         const ONE: Self;
+
+        fn non_constant(value: usize) -> Self {
+            let mut res = Self::ZERO;
+            let mut count = 0;
+            while count < value {
+                res = res + Self::ONE;
+                //~^ assign_op_pattern
+                count = count + 1;
+                //~^ assign_op_pattern
+            }
+            res
+        }
     }
 
     #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet)
@@ -91,16 +104,36 @@ mod issue14871 {
 
     impl<T> const NumberConstants for T
     where
-        T: Number + [const] core::ops::Add,
+        T: Number + [const] std::ops::Add,
     {
         fn constant(value: usize) -> Self {
             let mut res = Self::ZERO;
             let mut count = 0;
             while count < value {
                 res = res + Self::ONE;
-                count += 1;
+                count = count + 1;
+                //~^ assign_op_pattern
             }
             res
         }
     }
+
+    pub struct S;
+
+    impl const std::ops::Add for S {
+        type Output = S;
+        fn add(self, _rhs: S) -> S {
+            S
+        }
+    }
+
+    impl const std::ops::AddAssign for S {
+        fn add_assign(&mut self, rhs: S) {}
+    }
+
+    const fn do_add() {
+        let mut s = S;
+        s = s + S;
+        //~^ assign_op_pattern
+    }
 }
diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr
index c5e698b3ee1..a4fca04893c 100644
--- a/src/tools/clippy/tests/ui/assign_ops.stderr
+++ b/src/tools/clippy/tests/ui/assign_ops.stderr
@@ -1,5 +1,5 @@
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:10:5
+  --> tests/ui/assign_ops.rs:11:5
    |
 LL |     a = a + 1;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
@@ -8,70 +8,94 @@ LL |     a = a + 1;
    = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:12:5
+  --> tests/ui/assign_ops.rs:13:5
    |
 LL |     a = 1 + a;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:14:5
+  --> tests/ui/assign_ops.rs:15:5
    |
 LL |     a = a - 1;
    |     ^^^^^^^^^ help: replace it with: `a -= 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:16:5
+  --> tests/ui/assign_ops.rs:17:5
    |
 LL |     a = a * 99;
    |     ^^^^^^^^^^ help: replace it with: `a *= 99`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:18:5
+  --> tests/ui/assign_ops.rs:19:5
    |
 LL |     a = 42 * a;
    |     ^^^^^^^^^^ help: replace it with: `a *= 42`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:20:5
+  --> tests/ui/assign_ops.rs:21:5
    |
 LL |     a = a / 2;
    |     ^^^^^^^^^ help: replace it with: `a /= 2`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:22:5
+  --> tests/ui/assign_ops.rs:23:5
    |
 LL |     a = a % 5;
    |     ^^^^^^^^^ help: replace it with: `a %= 5`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:24:5
+  --> tests/ui/assign_ops.rs:25:5
    |
 LL |     a = a & 1;
    |     ^^^^^^^^^ help: replace it with: `a &= 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:31:5
+  --> tests/ui/assign_ops.rs:32:5
    |
 LL |     s = s + "bla";
    |     ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:36:5
+  --> tests/ui/assign_ops.rs:37:5
    |
 LL |     a = a + Wrapping(1u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:39:5
+  --> tests/ui/assign_ops.rs:40:5
    |
 LL |     v[0] = v[0] + v[1];
    |     ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:52:5
+  --> tests/ui/assign_ops.rs:53:5
    |
 LL |     buf = buf + cows.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
 
-error: aborting due to 12 previous errors
+error: manual implementation of an assign operation
+  --> tests/ui/assign_ops.rs:91:17
+   |
+LL |                 res = res + Self::ONE;
+   |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `res += Self::ONE`
+
+error: manual implementation of an assign operation
+  --> tests/ui/assign_ops.rs:93:17
+   |
+LL |                 count = count + 1;
+   |                 ^^^^^^^^^^^^^^^^^ help: replace it with: `count += 1`
+
+error: manual implementation of an assign operation
+  --> tests/ui/assign_ops.rs:114:17
+   |
+LL |                 count = count + 1;
+   |                 ^^^^^^^^^^^^^^^^^ help: replace it with: `count += 1`
+
+error: manual implementation of an assign operation
+  --> tests/ui/assign_ops.rs:136:9
+   |
+LL |         s = s + S;
+   |         ^^^^^^^^^ help: replace it with: `s += S`
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed
index 93c573d3086..bd1b31f74ee 100644
--- a/src/tools/clippy/tests/ui/async_yields_async.fixed
+++ b/src/tools/clippy/tests/ui/async_yields_async.fixed
@@ -80,3 +80,42 @@ fn check_expect_suppression() {
         }
     };
 }
+
+#[allow(clippy::let_underscore_future)]
+fn issue15552() {
+    async fn bar(i: i32) {}
+
+    macro_rules! call_bar {
+        () => {
+            async { bar(5).await }
+        };
+        ($e:expr) => {
+            bar($e)
+        };
+    }
+    let x = async { call_bar!(5).await };
+    //~^ async_yields_async
+    let y = async { call_bar!().await };
+    //~^ async_yields_async
+    //~| async_yields_async
+
+    use std::future::{Future, Ready};
+    use std::ops::Add;
+    use std::pin::Pin;
+    use std::task::{Context, Poll};
+    struct CustomFutureType;
+    impl Add for CustomFutureType {
+        type Output = Self;
+        fn add(self, other: Self) -> Self {
+            self
+        }
+    }
+    impl Future for CustomFutureType {
+        type Output = ();
+        fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
+            Poll::Ready(())
+        }
+    }
+    let _ = async { (CustomFutureType + CustomFutureType).await };
+    //~^ async_yields_async
+}
diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs
index 166d522e1c0..605d2734157 100644
--- a/src/tools/clippy/tests/ui/async_yields_async.rs
+++ b/src/tools/clippy/tests/ui/async_yields_async.rs
@@ -80,3 +80,42 @@ fn check_expect_suppression() {
         }
     };
 }
+
+#[allow(clippy::let_underscore_future)]
+fn issue15552() {
+    async fn bar(i: i32) {}
+
+    macro_rules! call_bar {
+        () => {
+            async { bar(5) }
+        };
+        ($e:expr) => {
+            bar($e)
+        };
+    }
+    let x = async { call_bar!(5) };
+    //~^ async_yields_async
+    let y = async { call_bar!() };
+    //~^ async_yields_async
+    //~| async_yields_async
+
+    use std::future::{Future, Ready};
+    use std::ops::Add;
+    use std::pin::Pin;
+    use std::task::{Context, Poll};
+    struct CustomFutureType;
+    impl Add for CustomFutureType {
+        type Output = Self;
+        fn add(self, other: Self) -> Self {
+            self
+        }
+    }
+    impl Future for CustomFutureType {
+        type Output = ();
+        fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
+            Poll::Ready(())
+        }
+    }
+    let _ = async { CustomFutureType + CustomFutureType };
+    //~^ async_yields_async
+}
diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr
index 17a35076fa3..3041cf65789 100644
--- a/src/tools/clippy/tests/ui/async_yields_async.stderr
+++ b/src/tools/clippy/tests/ui/async_yields_async.stderr
@@ -89,5 +89,50 @@ LL | |         CustomFutureType
 LL | |     };
    | |_____- outer async construct
 
-error: aborting due to 6 previous errors
+error: an async construct yields a type which is itself awaitable
+  --> tests/ui/async_yields_async.rs:96:21
+   |
+LL |     let x = async { call_bar!(5) };
+   |                   --^^^^^^^^^^^^--
+   |                   | |
+   |                   | awaitable value not awaited
+   |                   | help: consider awaiting this value: `call_bar!(5).await`
+   |                   outer async construct
+
+error: an async construct yields a type which is itself awaitable
+  --> tests/ui/async_yields_async.rs:98:21
+   |
+LL |     let y = async { call_bar!() };
+   |                   --^^^^^^^^^^^--
+   |                   | |
+   |                   | awaitable value not awaited
+   |                   | help: consider awaiting this value: `call_bar!().await`
+   |                   outer async construct
+
+error: an async construct yields a type which is itself awaitable
+  --> tests/ui/async_yields_async.rs:90:21
+   |
+LL |             async { bar(5) }
+   |                   --^^^^^^--
+   |                   | |
+   |                   | awaitable value not awaited
+   |                   | help: consider awaiting this value: `bar(5).await`
+   |                   outer async construct
+...
+LL |     let y = async { call_bar!() };
+   |                     ----------- in this macro invocation
+   |
+   = note: this error originates in the macro `call_bar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: an async construct yields a type which is itself awaitable
+  --> tests/ui/async_yields_async.rs:119:21
+   |
+LL |     let _ = async { CustomFutureType + CustomFutureType };
+   |                   --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--
+   |                   | |
+   |                   | awaitable value not awaited
+   |                   | help: consider awaiting this value: `(CustomFutureType + CustomFutureType).await`
+   |                   outer async construct
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
index f823f08f31d..72aa6303a20 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
@@ -272,10 +272,8 @@ LL |     assert_eq!(a!(), true);
    |
 help: replace it with `assert!(..)`
    |
-LL |         true
-...
-LL |
-LL ~     assert!(a!());
+LL -     assert_eq!(a!(), true);
+LL +     assert!(a!());
    |
 
 error: used `assert_eq!` with a literal bool
@@ -286,10 +284,8 @@ LL |     assert_eq!(true, b!());
    |
 help: replace it with `assert!(..)`
    |
-LL |         true
-...
-LL |
-LL ~     assert!(b!());
+LL -     assert_eq!(true, b!());
+LL +     assert!(b!());
    |
 
 error: used `debug_assert_eq!` with a literal bool
diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed
index 166abbe549c..b0b60104c0b 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.fixed
+++ b/src/tools/clippy/tests/ui/bool_comparison.fixed
@@ -1,97 +1,41 @@
 #![allow(non_local_definitions, clippy::needless_if)]
 #![warn(clippy::bool_comparison)]
-#![allow(clippy::non_canonical_partial_ord_impl, clippy::nonminimal_bool)]
+#![allow(clippy::non_canonical_partial_ord_impl)]
 
 fn main() {
     let x = true;
-    if x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if !x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if !x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if !x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if !x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if !x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if !x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
+    let _ = if x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if !x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if !x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if !x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if !x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if !x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if !x { "yes" } else { "no" };
+    //~^ bool_comparison
+
     let y = true;
-    if !x & y {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x & !y {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
+    let _ = if !x & y { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x & !y { "yes" } else { "no" };
+    //~^ bool_comparison
 }
 
-#[allow(dead_code)]
 fn issue3703() {
     struct Foo;
     impl PartialEq<bool> for Foo {
@@ -127,26 +71,6 @@ fn issue3703() {
     if false < Foo {}
 }
 
-#[allow(dead_code)]
-fn issue4983() {
-    let a = true;
-    let b = false;
-
-    if a != b {};
-    //~^ bool_comparison
-    if a != b {};
-    //~^ bool_comparison
-    if a == b {};
-    if !a == !b {};
-
-    if b != a {};
-    //~^ bool_comparison
-    if b != a {};
-    //~^ bool_comparison
-    if b == a {};
-    if !b == !a {};
-}
-
 macro_rules! m {
     ($func:ident) => {
         $func()
@@ -157,7 +81,6 @@ fn func() -> bool {
     true
 }
 
-#[allow(dead_code)]
 fn issue3973() {
     // ok, don't lint on `cfg` invocation
     if false == cfg!(feature = "debugging") {}
@@ -196,6 +119,34 @@ fn issue9907() {
     //~^ bool_comparison
     // This is not part of the issue, but an unexpected found when fixing the issue,
     // the provided span was inside of macro rather than the macro callsite.
-    let _ = ((1 < 2) != m!(func)) as usize;
+    let _ = ((1 < 2) & !m!(func)) as usize;
     //~^ bool_comparison
 }
+
+#[allow(clippy::nonminimal_bool)]
+fn issue15367() {
+    let a = true;
+    let b = false;
+
+    // these cases are handled by `nonminimal_bool`, so don't double-lint
+    if a == !b {};
+    if !a == b {};
+    if b == !a {};
+    if !b == a {};
+}
+
+fn issue15497() {
+    fn func() -> bool {
+        true
+    }
+
+    fn foo(x: bool) -> bool {
+        x & !m!(func)
+        //~^ bool_comparison
+    }
+
+    fn bar(x: bool) -> bool {
+        !x & m!(func)
+        //~^ bool_comparison
+    }
+}
diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs
index 7265c2b4c5a..1b1108d6ce5 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_comparison.rs
@@ -1,97 +1,41 @@
 #![allow(non_local_definitions, clippy::needless_if)]
 #![warn(clippy::bool_comparison)]
-#![allow(clippy::non_canonical_partial_ord_impl, clippy::nonminimal_bool)]
+#![allow(clippy::non_canonical_partial_ord_impl)]
 
 fn main() {
     let x = true;
-    if x == true {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x == false {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if true == x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if false == x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x != true {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x != false {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if true != x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if false != x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x < true {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if false < x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x > false {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if true > x {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
+    let _ = if x == true { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x == false { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if true == x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if false == x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x != true { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x != false { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if true != x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if false != x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x < true { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if false < x { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x > false { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if true > x { "yes" } else { "no" };
+    //~^ bool_comparison
+
     let y = true;
-    if x < y {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
-    if x > y {
-        //~^ bool_comparison
-        "yes"
-    } else {
-        "no"
-    };
+    let _ = if x < y { "yes" } else { "no" };
+    //~^ bool_comparison
+    let _ = if x > y { "yes" } else { "no" };
+    //~^ bool_comparison
 }
 
-#[allow(dead_code)]
 fn issue3703() {
     struct Foo;
     impl PartialEq<bool> for Foo {
@@ -127,26 +71,6 @@ fn issue3703() {
     if false < Foo {}
 }
 
-#[allow(dead_code)]
-fn issue4983() {
-    let a = true;
-    let b = false;
-
-    if a == !b {};
-    //~^ bool_comparison
-    if !a == b {};
-    //~^ bool_comparison
-    if a == b {};
-    if !a == !b {};
-
-    if b == !a {};
-    //~^ bool_comparison
-    if !b == a {};
-    //~^ bool_comparison
-    if b == a {};
-    if !b == !a {};
-}
-
 macro_rules! m {
     ($func:ident) => {
         $func()
@@ -157,7 +81,6 @@ fn func() -> bool {
     true
 }
 
-#[allow(dead_code)]
 fn issue3973() {
     // ok, don't lint on `cfg` invocation
     if false == cfg!(feature = "debugging") {}
@@ -196,6 +119,34 @@ fn issue9907() {
     //~^ bool_comparison
     // This is not part of the issue, but an unexpected found when fixing the issue,
     // the provided span was inside of macro rather than the macro callsite.
-    let _ = ((1 < 2) == !m!(func)) as usize;
+    let _ = ((1 < 2) > m!(func)) as usize;
     //~^ bool_comparison
 }
+
+#[allow(clippy::nonminimal_bool)]
+fn issue15367() {
+    let a = true;
+    let b = false;
+
+    // these cases are handled by `nonminimal_bool`, so don't double-lint
+    if a == !b {};
+    if !a == b {};
+    if b == !a {};
+    if !b == a {};
+}
+
+fn issue15497() {
+    fn func() -> bool {
+        true
+    }
+
+    fn foo(x: bool) -> bool {
+        x > m!(func)
+        //~^ bool_comparison
+    }
+
+    fn bar(x: bool) -> bool {
+        x < m!(func)
+        //~^ bool_comparison
+    }
+}
diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr
index ddbb9ff78ed..98881a2d20f 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_comparison.stderr
@@ -1,155 +1,143 @@
 error: equality checks against true are unnecessary
-  --> tests/ui/bool_comparison.rs:7:8
+  --> tests/ui/bool_comparison.rs:7:16
    |
-LL |     if x == true {
-   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+LL |     let _ = if x == true { "yes" } else { "no" };
+   |                ^^^^^^^^^ help: try: `x`
    |
    = note: `-D clippy::bool-comparison` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
 
 error: equality checks against false can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:13:8
+  --> tests/ui/bool_comparison.rs:9:16
    |
-LL |     if x == false {
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+LL |     let _ = if x == false { "yes" } else { "no" };
+   |                ^^^^^^^^^^ help: try: `!x`
 
 error: equality checks against true are unnecessary
-  --> tests/ui/bool_comparison.rs:19:8
+  --> tests/ui/bool_comparison.rs:11:16
    |
-LL |     if true == x {
-   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+LL |     let _ = if true == x { "yes" } else { "no" };
+   |                ^^^^^^^^^ help: try: `x`
 
 error: equality checks against false can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:25:8
+  --> tests/ui/bool_comparison.rs:13:16
    |
-LL |     if false == x {
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+LL |     let _ = if false == x { "yes" } else { "no" };
+   |                ^^^^^^^^^^ help: try: `!x`
 
 error: inequality checks against true can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:31:8
+  --> tests/ui/bool_comparison.rs:15:16
    |
-LL |     if x != true {
-   |        ^^^^^^^^^ help: try simplifying it as shown: `!x`
+LL |     let _ = if x != true { "yes" } else { "no" };
+   |                ^^^^^^^^^ help: try: `!x`
 
 error: inequality checks against false are unnecessary
-  --> tests/ui/bool_comparison.rs:37:8
+  --> tests/ui/bool_comparison.rs:17:16
    |
-LL |     if x != false {
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `x`
+LL |     let _ = if x != false { "yes" } else { "no" };
+   |                ^^^^^^^^^^ help: try: `x`
 
 error: inequality checks against true can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:43:8
+  --> tests/ui/bool_comparison.rs:19:16
    |
-LL |     if true != x {
-   |        ^^^^^^^^^ help: try simplifying it as shown: `!x`
+LL |     let _ = if true != x { "yes" } else { "no" };
+   |                ^^^^^^^^^ help: try: `!x`
 
 error: inequality checks against false are unnecessary
-  --> tests/ui/bool_comparison.rs:49:8
+  --> tests/ui/bool_comparison.rs:21:16
    |
-LL |     if false != x {
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `x`
+LL |     let _ = if false != x { "yes" } else { "no" };
+   |                ^^^^^^^^^^ help: try: `x`
 
 error: less than comparison against true can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:55:8
+  --> tests/ui/bool_comparison.rs:23:16
    |
-LL |     if x < true {
-   |        ^^^^^^^^ help: try simplifying it as shown: `!x`
+LL |     let _ = if x < true { "yes" } else { "no" };
+   |                ^^^^^^^^ help: try: `!x`
 
 error: greater than checks against false are unnecessary
-  --> tests/ui/bool_comparison.rs:61:8
+  --> tests/ui/bool_comparison.rs:25:16
    |
-LL |     if false < x {
-   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+LL |     let _ = if false < x { "yes" } else { "no" };
+   |                ^^^^^^^^^ help: try: `x`
 
 error: greater than checks against false are unnecessary
-  --> tests/ui/bool_comparison.rs:67:8
+  --> tests/ui/bool_comparison.rs:27:16
    |
-LL |     if x > false {
-   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+LL |     let _ = if x > false { "yes" } else { "no" };
+   |                ^^^^^^^^^ help: try: `x`
 
 error: less than comparison against true can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:73:8
+  --> tests/ui/bool_comparison.rs:29:16
    |
-LL |     if true > x {
-   |        ^^^^^^^^ help: try simplifying it as shown: `!x`
+LL |     let _ = if true > x { "yes" } else { "no" };
+   |                ^^^^^^^^ help: try: `!x`
 
 error: order comparisons between booleans can be simplified
-  --> tests/ui/bool_comparison.rs:80:8
+  --> tests/ui/bool_comparison.rs:33:16
    |
-LL |     if x < y {
-   |        ^^^^^ help: try simplifying it as shown: `!x & y`
+LL |     let _ = if x < y { "yes" } else { "no" };
+   |                ^^^^^ help: try: `!x & y`
 
 error: order comparisons between booleans can be simplified
-  --> tests/ui/bool_comparison.rs:86:8
+  --> tests/ui/bool_comparison.rs:35:16
    |
-LL |     if x > y {
-   |        ^^^^^ help: try simplifying it as shown: `x & !y`
-
-error: this comparison might be written more concisely
-  --> tests/ui/bool_comparison.rs:135:8
-   |
-LL |     if a == !b {};
-   |        ^^^^^^^ help: try simplifying it as shown: `a != b`
-
-error: this comparison might be written more concisely
-  --> tests/ui/bool_comparison.rs:137:8
-   |
-LL |     if !a == b {};
-   |        ^^^^^^^ help: try simplifying it as shown: `a != b`
-
-error: this comparison might be written more concisely
-  --> tests/ui/bool_comparison.rs:142:8
-   |
-LL |     if b == !a {};
-   |        ^^^^^^^ help: try simplifying it as shown: `b != a`
-
-error: this comparison might be written more concisely
-  --> tests/ui/bool_comparison.rs:144:8
-   |
-LL |     if !b == a {};
-   |        ^^^^^^^ help: try simplifying it as shown: `b != a`
+LL |     let _ = if x > y { "yes" } else { "no" };
+   |                ^^^^^ help: try: `x & !y`
 
 error: equality checks against false can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:169:8
+  --> tests/ui/bool_comparison.rs:92:8
    |
 LL |     if false == m!(func) {}
-   |        ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
+   |        ^^^^^^^^^^^^^^^^^ help: try: `!m!(func)`
 
 error: equality checks against false can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:171:8
+  --> tests/ui/bool_comparison.rs:94:8
    |
 LL |     if m!(func) == false {}
-   |        ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
+   |        ^^^^^^^^^^^^^^^^^ help: try: `!m!(func)`
 
 error: equality checks against true are unnecessary
-  --> tests/ui/bool_comparison.rs:173:8
+  --> tests/ui/bool_comparison.rs:96:8
    |
 LL |     if true == m!(func) {}
-   |        ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
+   |        ^^^^^^^^^^^^^^^^ help: try: `m!(func)`
 
 error: equality checks against true are unnecessary
-  --> tests/ui/bool_comparison.rs:175:8
+  --> tests/ui/bool_comparison.rs:98:8
    |
 LL |     if m!(func) == true {}
-   |        ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
+   |        ^^^^^^^^^^^^^^^^ help: try: `m!(func)`
 
 error: equality checks against false can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:193:14
+  --> tests/ui/bool_comparison.rs:116:14
    |
 LL |     let _ = ((1 < 2) == false) as usize;
-   |              ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `1 >= 2`
+   |              ^^^^^^^^^^^^^^^^ help: try: `1 >= 2`
 
 error: equality checks against false can be replaced by a negation
-  --> tests/ui/bool_comparison.rs:195:14
+  --> tests/ui/bool_comparison.rs:118:14
    |
 LL |     let _ = (false == m!(func)) as usize;
-   |              ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
+   |              ^^^^^^^^^^^^^^^^^ help: try: `!m!(func)`
 
-error: this comparison might be written more concisely
-  --> tests/ui/bool_comparison.rs:199:14
+error: order comparisons between booleans can be simplified
+  --> tests/ui/bool_comparison.rs:122:14
+   |
+LL |     let _ = ((1 < 2) > m!(func)) as usize;
+   |              ^^^^^^^^^^^^^^^^^^ help: try: `(1 < 2) & !m!(func)`
+
+error: order comparisons between booleans can be simplified
+  --> tests/ui/bool_comparison.rs:144:9
+   |
+LL |         x > m!(func)
+   |         ^^^^^^^^^^^^ help: try: `x & !m!(func)`
+
+error: order comparisons between booleans can be simplified
+  --> tests/ui/bool_comparison.rs:149:9
    |
-LL |     let _ = ((1 < 2) == !m!(func)) as usize;
-   |              ^^^^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `(1 < 2) != m!(func)`
+LL |         x < m!(func)
+   |         ^^^^^^^^^^^^ help: try: `!x & m!(func)`
 
-error: aborting due to 25 previous errors
+error: aborting due to 23 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed
index bddcb0ebf64..3c1cf884595 100644
--- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed
@@ -1,30 +1,53 @@
 #![warn(clippy::cast_slice_from_raw_parts)]
 
-#[allow(unused_imports, unused_unsafe)]
+const fn require_raw_slice_ptr<T>(_: *const [T]) {}
+
 fn main() {
     let mut vec = vec![0u8; 1];
     let ptr: *const u8 = vec.as_ptr();
     let mptr = vec.as_mut_ptr();
-    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
+    let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(ptr, 1) };
     //~^ cast_slice_from_raw_parts
-    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
+    let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(mptr, 1) };
     //~^ cast_slice_from_raw_parts
-    let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1);
     //~^ cast_slice_from_raw_parts
     {
         use core::slice;
-        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1);
         //~^ cast_slice_from_raw_parts
         use slice as one;
-        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1);
         //~^ cast_slice_from_raw_parts
     }
     {
         use std::slice;
-        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1);
         //~^ cast_slice_from_raw_parts
         use slice as one;
-        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1);
         //~^ cast_slice_from_raw_parts
     }
+
+    // implicit cast
+    {
+        let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(ptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(mptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { std::ptr::slice_from_raw_parts(ptr, 1) });
+        //~^ cast_slice_from_raw_parts
+    }
+
+    // implicit cast in const context
+    const {
+        const PTR: *const u8 = std::ptr::null();
+        const MPTR: *mut u8 = std::ptr::null_mut();
+        let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(PTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(MPTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { std::ptr::slice_from_raw_parts(PTR, 1) });
+        //~^ cast_slice_from_raw_parts
+    };
 }
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs
index 0a1eb276d5e..8f57b1f9619 100644
--- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs
@@ -1,6 +1,7 @@
 #![warn(clippy::cast_slice_from_raw_parts)]
 
-#[allow(unused_imports, unused_unsafe)]
+const fn require_raw_slice_ptr<T>(_: *const [T]) {}
+
 fn main() {
     let mut vec = vec![0u8; 1];
     let ptr: *const u8 = vec.as_ptr();
@@ -27,4 +28,26 @@ fn main() {
         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
         //~^ cast_slice_from_raw_parts
     }
+
+    // implicit cast
+    {
+        let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) });
+        //~^ cast_slice_from_raw_parts
+    }
+
+    // implicit cast in const context
+    const {
+        const PTR: *const u8 = std::ptr::null();
+        const MPTR: *mut u8 = std::ptr::null_mut();
+        let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) });
+        //~^ cast_slice_from_raw_parts
+    };
 }
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr
index 60794a988db..328dbafbafe 100644
--- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr
@@ -1,47 +1,83 @@
 error: casting the result of `from_raw_parts` to *const [u8]
-  --> tests/ui/cast_raw_slice_pointer_cast.rs:8:35
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:9:35
    |
 LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)`
    |
    = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]`
 
 error: casting the result of `from_raw_parts_mut` to *mut [u8]
-  --> tests/ui/cast_raw_slice_pointer_cast.rs:10:35
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:11:35
    |
 LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts_mut(mptr, 1)`
 
 error: casting the result of `from_raw_parts` to *const [u8]
-  --> tests/ui/cast_raw_slice_pointer_cast.rs:12:26
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:13:26
    |
 LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)`
 
 error: casting the result of `from_raw_parts` to *const [u8]
-  --> tests/ui/cast_raw_slice_pointer_cast.rs:16:30
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:17:30
    |
 LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)`
 
 error: casting the result of `from_raw_parts` to *const [u8]
-  --> tests/ui/cast_raw_slice_pointer_cast.rs:19:30
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:20:30
    |
 LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)`
 
 error: casting the result of `from_raw_parts` to *const [u8]
-  --> tests/ui/cast_raw_slice_pointer_cast.rs:24:30
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:25:30
    |
 LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)`
 
 error: casting the result of `from_raw_parts` to *const [u8]
-  --> tests/ui/cast_raw_slice_pointer_cast.rs:27:30
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:28:30
    |
 LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)`
 
-error: aborting due to 7 previous errors
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:34:39
+   |
+LL |         let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) };
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:36:37
+   |
+LL |         let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) };
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts_mut(mptr, 1)`
+
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:38:40
+   |
+LL |         require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) });
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:46:39
+   |
+LL |         let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) };
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)`
+
+error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:48:37
+   |
+LL |         let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) };
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts_mut(MPTR, 1)`
+
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast.rs:50:40
+   |
+LL |         require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) });
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)`
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.fixed
new file mode 100644
index 00000000000..f71fb8d863c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.fixed
@@ -0,0 +1,55 @@
+#![warn(clippy::cast_slice_from_raw_parts)]
+#![no_std]
+#![crate_type = "lib"]
+
+const fn require_raw_slice_ptr<T>(_: *const [T]) {}
+
+fn main() {
+    let mut arr = [0u8; 1];
+    let ptr: *const u8 = arr.as_ptr();
+    let mptr = arr.as_mut_ptr();
+    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
+    //~^ cast_slice_from_raw_parts
+    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
+    //~^ cast_slice_from_raw_parts
+    let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    //~^ cast_slice_from_raw_parts
+    {
+        use core::slice;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        //~^ cast_slice_from_raw_parts
+        use slice as one;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        //~^ cast_slice_from_raw_parts
+    }
+    {
+        use core::slice;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        //~^ cast_slice_from_raw_parts
+        use slice as one;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        //~^ cast_slice_from_raw_parts
+    }
+
+    // implicit cast
+    {
+        let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { core::ptr::slice_from_raw_parts(ptr, 1) });
+        //~^ cast_slice_from_raw_parts
+    }
+
+    // implicit cast in const context
+    const {
+        const PTR: *const u8 = core::ptr::null();
+        const MPTR: *mut u8 = core::ptr::null_mut();
+        let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(PTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(MPTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { core::ptr::slice_from_raw_parts(PTR, 1) });
+        //~^ cast_slice_from_raw_parts
+    };
+}
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.rs
new file mode 100644
index 00000000000..743e44c97dc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.rs
@@ -0,0 +1,55 @@
+#![warn(clippy::cast_slice_from_raw_parts)]
+#![no_std]
+#![crate_type = "lib"]
+
+const fn require_raw_slice_ptr<T>(_: *const [T]) {}
+
+fn main() {
+    let mut arr = [0u8; 1];
+    let ptr: *const u8 = arr.as_ptr();
+    let mptr = arr.as_mut_ptr();
+    let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) as *const [u8] };
+    //~^ cast_slice_from_raw_parts
+    let _: *const [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+    //~^ cast_slice_from_raw_parts
+    let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) } as *const [u8];
+    //~^ cast_slice_from_raw_parts
+    {
+        use core::slice;
+        let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+        //~^ cast_slice_from_raw_parts
+        use slice as one;
+        let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+        //~^ cast_slice_from_raw_parts
+    }
+    {
+        use core::slice;
+        let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+        //~^ cast_slice_from_raw_parts
+        use slice as one;
+        let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+        //~^ cast_slice_from_raw_parts
+    }
+
+    // implicit cast
+    {
+        let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(ptr, 1) });
+        //~^ cast_slice_from_raw_parts
+    }
+
+    // implicit cast in const context
+    const {
+        const PTR: *const u8 = core::ptr::null();
+        const MPTR: *mut u8 = core::ptr::null_mut();
+        let _: *const [u8] = unsafe { core::slice::from_raw_parts(PTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(MPTR, 1) };
+        //~^ cast_slice_from_raw_parts
+        require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(PTR, 1) });
+        //~^ cast_slice_from_raw_parts
+    };
+}
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.stderr
new file mode 100644
index 00000000000..5488fbcfa1c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.stderr
@@ -0,0 +1,83 @@
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:11:35
+   |
+LL |     let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) as *const [u8] };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |
+   = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]`
+
+error: casting the result of `from_raw_parts_mut` to *mut [u8]
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:13:35
+   |
+LL |     let _: *const [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:15:26
+   |
+LL |     let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:19:30
+   |
+LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:22:30
+   |
+LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:27:30
+   |
+LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:30:30
+   |
+LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:36:39
+   |
+LL |         let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) };
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:38:37
+   |
+LL |         let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) };
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
+
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:40:40
+   |
+LL |         require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(ptr, 1) });
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:48:39
+   |
+LL |         let _: *const [u8] = unsafe { core::slice::from_raw_parts(PTR, 1) };
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(PTR, 1)`
+
+error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:50:37
+   |
+LL |         let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(MPTR, 1) };
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts_mut(MPTR, 1)`
+
+error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
+  --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:52:40
+   |
+LL |         require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(PTR, 1) });
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(PTR, 1)`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 71b82040ff6..8931a3aa09c 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -316,6 +316,47 @@ fn lint_emitted_at_right_node(opt: Option<Result<u64, String>>) {
     };
 }
 
+pub fn issue_14155() {
+    let mut arr = ["a", "b", "c"];
+    if let Some(last) = arr.last() {
+        match *last {
+            //~^ collapsible_match
+            "a" | "b" => {
+                unimplemented!()
+            },
+            _ => (),
+        }
+    }
+
+    if let Some(last) = arr.last() {
+        match &last {
+            //~^ collapsible_match
+            &&"a" | &&"b" => {
+                unimplemented!()
+            },
+            _ => (),
+        }
+    }
+
+    if let Some(mut last) = arr.last_mut() {
+        match &mut last {
+            //~^ collapsible_match
+            &mut &mut "a" | &mut &mut "b" => {
+                unimplemented!()
+            },
+            _ => (),
+        }
+    }
+
+    const NULL_PTR: *const &'static str = std::ptr::null();
+    if let Some(last) = arr.last() {
+        match &raw const *last {
+            NULL_PTR => unimplemented!(),
+            _ => (),
+        }
+    }
+}
+
 fn make<T>() -> T {
     unimplemented!()
 }
diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr
index c290d84ec29..14b1c1b187e 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match.stderr
@@ -250,5 +250,74 @@ LL |     if let Issue9647::A { a: Some(a), .. } = x {
 LL |         if let Some(u) = a {
    |                ^^^^^^^ with this pattern
 
-error: aborting due to 13 previous errors
+error: this `match` can be collapsed into the outer `if let`
+  --> tests/ui/collapsible_match.rs:322:9
+   |
+LL | /         match *last {
+LL | |
+LL | |             "a" | "b" => {
+LL | |                 unimplemented!()
+LL | |             },
+LL | |             _ => (),
+LL | |         }
+   | |_________^
+   |
+help: the outer pattern can be modified to include the inner pattern
+  --> tests/ui/collapsible_match.rs:321:17
+   |
+LL |     if let Some(last) = arr.last() {
+   |                 ^^^^    ---------- use: `arr.last().copied()`
+   |                 |
+   |                 replace this binding
+...
+LL |             "a" | "b" => {
+   |             ^^^^^^^^^ with this pattern
+
+error: this `match` can be collapsed into the outer `if let`
+  --> tests/ui/collapsible_match.rs:332:9
+   |
+LL | /         match &last {
+LL | |
+LL | |             &&"a" | &&"b" => {
+LL | |                 unimplemented!()
+LL | |             },
+LL | |             _ => (),
+LL | |         }
+   | |_________^
+   |
+help: the outer pattern can be modified to include the inner pattern
+  --> tests/ui/collapsible_match.rs:331:17
+   |
+LL |     if let Some(last) = arr.last() {
+   |                 ^^^^    ---------- use: `arr.last().as_ref()`
+   |                 |
+   |                 replace this binding
+...
+LL |             &&"a" | &&"b" => {
+   |             ^^^^^^^^^^^^^ with this pattern
+
+error: this `match` can be collapsed into the outer `if let`
+  --> tests/ui/collapsible_match.rs:342:9
+   |
+LL | /         match &mut last {
+LL | |
+LL | |             &mut &mut "a" | &mut &mut "b" => {
+LL | |                 unimplemented!()
+LL | |             },
+LL | |             _ => (),
+LL | |         }
+   | |_________^
+   |
+help: the outer pattern can be modified to include the inner pattern
+  --> tests/ui/collapsible_match.rs:341:17
+   |
+LL |     if let Some(mut last) = arr.last_mut() {
+   |                 ^^^^^^^^    -------------- use: `arr.last_mut().as_mut()`
+   |                 |
+   |                 replace this binding
+...
+LL |             &mut &mut "a" | &mut &mut "b" => {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ with this pattern
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr
index 7b273063752..25970670999 100644
--- a/src/tools/clippy/tests/ui/collapsible_match2.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr
@@ -77,6 +77,8 @@ LL | |         },
 help: the outer pattern can be modified to include the inner pattern
   --> tests/ui/collapsible_match2.rs:54:14
    |
+LL |     match Some(&[1]) {
+   |           ---------- use: `Some(&[1]).copied()`
 LL |         Some(s) => match *s {
    |              ^ replace this binding
 LL |
diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed
index 65bfded3883..9f9e4e253c3 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.fixed
+++ b/src/tools/clippy/tests/ui/derivable_impls.fixed
@@ -1,4 +1,6 @@
 #![allow(dead_code)]
+#![feature(const_trait_impl)]
+#![feature(const_default)]
 
 use std::collections::HashMap;
 
@@ -326,4 +328,40 @@ mod issue11368 {
     }
 }
 
+mod issue15493 {
+    #[derive(Copy, Clone)]
+    #[repr(transparent)]
+    struct Foo(u64);
+
+    impl const Default for Foo {
+        fn default() -> Self {
+            Self(0)
+        }
+    }
+
+    #[derive(Copy, Clone)]
+    enum Bar {
+        A,
+        B,
+    }
+
+    impl const Default for Bar {
+        fn default() -> Self {
+            Bar::A
+        }
+    }
+}
+
+mod issue15536 {
+    #[derive(Copy, Clone)]
+    #[derive(Default)]
+    enum Bar {
+        #[default]
+        A,
+        B,
+    }
+
+    
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs
index 4826c5497b4..74a793b9a70 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.rs
+++ b/src/tools/clippy/tests/ui/derivable_impls.rs
@@ -1,4 +1,6 @@
 #![allow(dead_code)]
+#![feature(const_trait_impl)]
+#![feature(const_default)]
 
 use std::collections::HashMap;
 
@@ -396,4 +398,43 @@ mod issue11368 {
     }
 }
 
+mod issue15493 {
+    #[derive(Copy, Clone)]
+    #[repr(transparent)]
+    struct Foo(u64);
+
+    impl const Default for Foo {
+        fn default() -> Self {
+            Self(0)
+        }
+    }
+
+    #[derive(Copy, Clone)]
+    enum Bar {
+        A,
+        B,
+    }
+
+    impl const Default for Bar {
+        fn default() -> Self {
+            Bar::A
+        }
+    }
+}
+
+mod issue15536 {
+    #[derive(Copy, Clone)]
+    enum Bar {
+        A,
+        B,
+    }
+
+    impl Default for Bar {
+        //~^ derivable_impls
+        fn default() -> Self {
+            Self::A
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr
index 0f73ad55a85..cd46414cb4a 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.stderr
+++ b/src/tools/clippy/tests/ui/derivable_impls.stderr
@@ -1,5 +1,5 @@
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:20:1
+  --> tests/ui/derivable_impls.rs:22:1
    |
 LL | / impl std::default::Default for FooDefault<'_> {
 LL | |
@@ -18,7 +18,7 @@ LL ~ struct FooDefault<'a> {
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:42:1
+  --> tests/ui/derivable_impls.rs:44:1
    |
 LL | / impl std::default::Default for TupleDefault {
 LL | |
@@ -35,7 +35,7 @@ LL ~ struct TupleDefault(bool, i32, u64);
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:95:1
+  --> tests/ui/derivable_impls.rs:97:1
    |
 LL | / impl Default for StrDefault<'_> {
 LL | |
@@ -52,7 +52,7 @@ LL ~ struct StrDefault<'a>(&'a str);
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:122:1
+  --> tests/ui/derivable_impls.rs:124:1
    |
 LL | / impl Default for Y {
 LL | |
@@ -69,7 +69,7 @@ LL ~ struct Y(u32);
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:162:1
+  --> tests/ui/derivable_impls.rs:164:1
    |
 LL | / impl Default for WithoutSelfCurly {
 LL | |
@@ -86,7 +86,7 @@ LL ~ struct WithoutSelfCurly {
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:171:1
+  --> tests/ui/derivable_impls.rs:173:1
    |
 LL | / impl Default for WithoutSelfParan {
 LL | |
@@ -103,7 +103,7 @@ LL ~ struct WithoutSelfParan(bool);
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:194:1
+  --> tests/ui/derivable_impls.rs:196:1
    |
 LL | / impl Default for DirectDefaultDefaultCall {
 LL | |
@@ -119,7 +119,7 @@ LL ~ pub struct DirectDefaultDefaultCall {
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:206:1
+  --> tests/ui/derivable_impls.rs:208:1
    |
 LL | / impl Default for EquivalentToDefaultDefaultCallVec {
 LL | |
@@ -135,7 +135,7 @@ LL ~ pub struct EquivalentToDefaultDefaultCallVec {
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:234:1
+  --> tests/ui/derivable_impls.rs:236:1
    |
 LL | / impl Default for EquivalentToDefaultDefaultCallLocal {
 LL | |
@@ -151,7 +151,7 @@ LL ~ pub struct EquivalentToDefaultDefaultCallLocal {
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:274:1
+  --> tests/ui/derivable_impls.rs:276:1
    |
 LL | / impl Default for RepeatDefault1 {
 LL | |
@@ -168,7 +168,7 @@ LL ~ pub struct RepeatDefault1 {
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:309:1
+  --> tests/ui/derivable_impls.rs:311:1
    |
 LL | / impl Default for SimpleEnum {
 LL | |
@@ -187,5 +187,28 @@ LL ~     #[default]
 LL ~     Bar,
    |
 
-error: aborting due to 11 previous errors
+error: this `impl` can be derived
+  --> tests/ui/derivable_impls.rs:432:5
+   |
+LL | /     impl Default for Bar {
+LL | |
+LL | |         fn default() -> Self {
+LL | |             Self::A
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: replace the manual implementation with a derive attribute and mark the default variant
+   |
+LL ~     #[derive(Default)]
+LL ~     enum Bar {
+LL ~         #[default]
+LL ~         A,
+LL |         B,
+LL |     }
+LL |
+LL ~     
+   |
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/derivable_impls_derive_const.fixed b/src/tools/clippy/tests/ui/derivable_impls_derive_const.fixed
new file mode 100644
index 00000000000..f0d8d2d2409
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derivable_impls_derive_const.fixed
@@ -0,0 +1,25 @@
+#![allow(dead_code)]
+#![feature(const_trait_impl)]
+#![feature(const_default)]
+#![feature(derive_const)]
+
+mod issue15493 {
+    #[derive(Copy, Clone)]
+    #[repr(transparent)]
+    #[derive_const(Default)]
+    struct Foo(u64);
+
+    
+
+    #[derive(Copy, Clone)]
+    #[derive_const(Default)]
+    enum Bar {
+        #[default]
+        A,
+        B,
+    }
+
+    
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls_derive_const.rs b/src/tools/clippy/tests/ui/derivable_impls_derive_const.rs
new file mode 100644
index 00000000000..7d70db1c097
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derivable_impls_derive_const.rs
@@ -0,0 +1,32 @@
+#![allow(dead_code)]
+#![feature(const_trait_impl)]
+#![feature(const_default)]
+#![feature(derive_const)]
+
+mod issue15493 {
+    #[derive(Copy, Clone)]
+    #[repr(transparent)]
+    struct Foo(u64);
+
+    impl const Default for Foo {
+        //~^ derivable_impls
+        fn default() -> Self {
+            Self(0)
+        }
+    }
+
+    #[derive(Copy, Clone)]
+    enum Bar {
+        A,
+        B,
+    }
+
+    impl const Default for Bar {
+        //~^ derivable_impls
+        fn default() -> Self {
+            Bar::A
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls_derive_const.stderr b/src/tools/clippy/tests/ui/derivable_impls_derive_const.stderr
new file mode 100644
index 00000000000..196bac185dd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derivable_impls_derive_const.stderr
@@ -0,0 +1,46 @@
+error: this `impl` can be derived
+  --> tests/ui/derivable_impls_derive_const.rs:11:5
+   |
+LL | /     impl const Default for Foo {
+LL | |
+LL | |         fn default() -> Self {
+LL | |             Self(0)
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::derivable-impls` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::derivable_impls)]`
+help: replace the manual implementation with a derive attribute
+   |
+LL ~     #[derive_const(Default)]
+LL ~     struct Foo(u64);
+LL |
+LL ~     
+   |
+
+error: this `impl` can be derived
+  --> tests/ui/derivable_impls_derive_const.rs:24:5
+   |
+LL | /     impl const Default for Bar {
+LL | |
+LL | |         fn default() -> Self {
+LL | |             Bar::A
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: replace the manual implementation with a derive attribute and mark the default variant
+   |
+LL ~     #[derive_const(Default)]
+LL ~     enum Bar {
+LL ~         #[default]
+LL ~         A,
+LL |         B,
+LL |     }
+LL |
+LL ~     
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 423a73734da..46695dc929a 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -73,6 +73,7 @@ fn test_units() {
 /// GPLv2 GPLv3
 /// GitHub GitLab
 /// IPv4 IPv6
+/// InfiniBand RoCE
 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript
 /// PowerPC WebAssembly
 /// NaN NaNs
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 8deffb4210e..4082fa5b56f 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -73,6 +73,7 @@ fn test_units() {
 /// GPLv2 GPLv3
 /// GitHub GitLab
 /// IPv4 IPv6
+/// InfiniBand RoCE
 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript
 /// PowerPC WebAssembly
 /// NaN NaNs
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
index 98c26e6bec2..2a94a8f3165 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
@@ -145,7 +145,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:90:5
+  --> tests/ui/doc/doc-fixable.rs:91:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:108:5
+  --> tests/ui/doc/doc-fixable.rs:109:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:117:8
+  --> tests/ui/doc/doc-fixable.rs:118:8
    |
 LL | /// ## CamelCaseThing
    |        ^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL + /// ## `CamelCaseThing`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:121:7
+  --> tests/ui/doc/doc-fixable.rs:122:7
    |
 LL | /// # CamelCaseThing
    |       ^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL + /// # `CamelCaseThing`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:124:22
+  --> tests/ui/doc/doc-fixable.rs:125:22
    |
 LL | /// Not a title #897 CamelCaseThing
    |                      ^^^^^^^^^^^^^^
@@ -205,7 +205,7 @@ LL + /// Not a title #897 `CamelCaseThing`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:126:5
+  --> tests/ui/doc/doc-fixable.rs:127:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -217,7 +217,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:134:5
+  --> tests/ui/doc/doc-fixable.rs:135:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:148:5
+  --> tests/ui/doc/doc-fixable.rs:149:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:160:43
+  --> tests/ui/doc/doc-fixable.rs:161:43
    |
 LL | /** E.g., serialization of an empty list: FooBar
    |                                           ^^^^^^
@@ -253,7 +253,7 @@ LL + /** E.g., serialization of an empty list: `FooBar`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:165:5
+  --> tests/ui/doc/doc-fixable.rs:166:5
    |
 LL | And BarQuz too.
    |     ^^^^^^
@@ -265,7 +265,7 @@ LL + And `BarQuz` too.
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:166:1
+  --> tests/ui/doc/doc-fixable.rs:167:1
    |
 LL | be_sure_we_got_to_the_end_of_it
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -277,7 +277,7 @@ LL + `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:174:43
+  --> tests/ui/doc/doc-fixable.rs:175:43
    |
 LL | /** E.g., serialization of an empty list: FooBar
    |                                           ^^^^^^
@@ -289,7 +289,7 @@ LL + /** E.g., serialization of an empty list: `FooBar`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:179:5
+  --> tests/ui/doc/doc-fixable.rs:180:5
    |
 LL | And BarQuz too.
    |     ^^^^^^
@@ -301,7 +301,7 @@ LL + And `BarQuz` too.
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:180:1
+  --> tests/ui/doc/doc-fixable.rs:181:1
    |
 LL | be_sure_we_got_to_the_end_of_it
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -313,7 +313,7 @@ LL + `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:194:5
+  --> tests/ui/doc/doc-fixable.rs:195:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -325,7 +325,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:214:22
+  --> tests/ui/doc/doc-fixable.rs:215:22
    |
 LL | /// An iterator over mycrate::Collection's values.
    |                      ^^^^^^^^^^^^^^^^^^^
@@ -337,7 +337,7 @@ LL + /// An iterator over `mycrate::Collection`'s values.
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:239:34
+  --> tests/ui/doc/doc-fixable.rs:240:34
    |
 LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint
    |                                  ^^^^^^^^^^^^^^^
@@ -349,7 +349,7 @@ LL + /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:263:22
+  --> tests/ui/doc/doc-fixable.rs:264:22
    |
 LL | /// There is no try (do() or do_not()).
    |                      ^^^^
@@ -361,7 +361,7 @@ LL + /// There is no try (`do()` or do_not()).
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:263:30
+  --> tests/ui/doc/doc-fixable.rs:264:30
    |
 LL | /// There is no try (do() or do_not()).
    |                              ^^^^^^^^
@@ -373,7 +373,7 @@ LL + /// There is no try (do() or `do_not()`).
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:268:5
+  --> tests/ui/doc/doc-fixable.rs:269:5
    |
 LL | /// ABes
    |     ^^^^
@@ -385,7 +385,7 @@ LL + /// `ABes`
    |
 
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc-fixable.rs:275:9
+  --> tests/ui/doc/doc-fixable.rs:276:9
    |
 LL |     /// foo()
    |         ^^^^^
@@ -397,7 +397,7 @@ LL +     /// `foo()`
    |
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> tests/ui/doc/doc-fixable.rs:280:5
+  --> tests/ui/doc/doc-fixable.rs:281:5
    |
 LL | /// https://github.com/rust-lang/rust-clippy/pull/12836
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `<https://github.com/rust-lang/rust-clippy/pull/12836>`
diff --git a/src/tools/clippy/tests/ui/entry_unfixable.stderr b/src/tools/clippy/tests/ui/entry_unfixable.stderr
index 0197d2ab4cf..f92f472512f 100644
--- a/src/tools/clippy/tests/ui/entry_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/entry_unfixable.stderr
@@ -10,6 +10,7 @@ LL | |                 false
 LL | |             }
    | |_____________^
    |
+   = help: consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.HashMap.html#entry-api
    = note: `-D clippy::map-entry` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::map_entry)]`
 
@@ -24,6 +25,8 @@ LL | |     } else {
 LL | |         hm.insert(key, true);
 LL | |     }
    | |_____^
+   |
+   = help: consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.HashMap.html#entry-api
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
   --> tests/ui/entry_unfixable.rs:80:13
@@ -36,6 +39,8 @@ LL | |                 let interner = INTERNER.lock().unwrap();
 LL | |                 return Err(interner.resolve(name).unwrap().to_owned());
 LL | |             }
    | |_____________^
+   |
+   = help: consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.HashMap.html#entry-api
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 3d2b41b8fb8..6944a979c05 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -565,6 +565,51 @@ fn issue_14789() {
     );
 }
 
+fn issue_15072() {
+    use std::ops::Deref;
+
+    struct Foo;
+    impl Deref for Foo {
+        type Target = fn() -> &'static str;
+
+        fn deref(&self) -> &Self::Target {
+            fn hello() -> &'static str {
+                "Hello, world!"
+            }
+            &(hello as fn() -> &'static str)
+        }
+    }
+
+    fn accepts_fn(f: impl Fn() -> &'static str) {
+        println!("{}", f());
+    }
+
+    fn some_fn() -> &'static str {
+        todo!()
+    }
+
+    let f = &Foo;
+    accepts_fn(**f);
+    //~^ redundant_closure
+
+    let g = &some_fn;
+    accepts_fn(g);
+    //~^ redundant_closure
+
+    struct Bar(Foo);
+    impl Deref for Bar {
+        type Target = Foo;
+
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    let b = &Bar(Foo);
+    accepts_fn(***b);
+    //~^ redundant_closure
+}
+
 fn issue8817() {
     fn f(_: u32) -> u32 {
         todo!()
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 79d1103410d..5bcc1cb26fd 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -565,6 +565,51 @@ fn issue_14789() {
     );
 }
 
+fn issue_15072() {
+    use std::ops::Deref;
+
+    struct Foo;
+    impl Deref for Foo {
+        type Target = fn() -> &'static str;
+
+        fn deref(&self) -> &Self::Target {
+            fn hello() -> &'static str {
+                "Hello, world!"
+            }
+            &(hello as fn() -> &'static str)
+        }
+    }
+
+    fn accepts_fn(f: impl Fn() -> &'static str) {
+        println!("{}", f());
+    }
+
+    fn some_fn() -> &'static str {
+        todo!()
+    }
+
+    let f = &Foo;
+    accepts_fn(|| f());
+    //~^ redundant_closure
+
+    let g = &some_fn;
+    accepts_fn(|| g());
+    //~^ redundant_closure
+
+    struct Bar(Foo);
+    impl Deref for Bar {
+        type Target = Foo;
+
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    let b = &Bar(Foo);
+    accepts_fn(|| b());
+    //~^ redundant_closure
+}
+
 fn issue8817() {
     fn f(_: u32) -> u32 {
         todo!()
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index aa32ed1a38e..0b401cdea98 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -215,28 +215,46 @@ LL |         let _field = bind.or_else(|| get_default()).unwrap();
    |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
 
 error: redundant closure
-  --> tests/ui/eta.rs:588:14
+  --> tests/ui/eta.rs:592:16
+   |
+LL |     accepts_fn(|| f());
+   |                ^^^^^^ help: replace the closure with the function itself: `**f`
+
+error: redundant closure
+  --> tests/ui/eta.rs:596:16
+   |
+LL |     accepts_fn(|| g());
+   |                ^^^^^^ help: replace the closure with the function itself: `g`
+
+error: redundant closure
+  --> tests/ui/eta.rs:609:16
+   |
+LL |     accepts_fn(|| b());
+   |                ^^^^^^ help: replace the closure with the function itself: `***b`
+
+error: redundant closure
+  --> tests/ui/eta.rs:633:14
    |
 LL |         .map(|n| MyError::A(n))
    |              ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A`
 
 error: redundant closure
-  --> tests/ui/eta.rs:585:14
+  --> tests/ui/eta.rs:630:14
    |
 LL |         .map(|n| S(n))
    |              ^^^^^^^^ help: replace the closure with the tuple struct itself: `S`
 
 error: redundant closure
-  --> tests/ui/eta.rs:582:14
+  --> tests/ui/eta.rs:627:14
    |
 LL |         .map(|n| g(n))
    |              ^^^^^^^^ help: replace the closure with the function itself: `g`
 
 error: redundant closure
-  --> tests/ui/eta.rs:579:14
+  --> tests/ui/eta.rs:624:14
    |
 LL |         .map(|n| f(n))
    |              ^^^^^^^^ help: replace the closure with the function itself: `f`
 
-error: aborting due to 39 previous errors
+error: aborting due to 42 previous errors
 
diff --git a/src/tools/clippy/tests/ui/excessive_precision.fixed b/src/tools/clippy/tests/ui/excessive_precision.fixed
index 8a8c2e1939c..8158d4b332a 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.fixed
+++ b/src/tools/clippy/tests/ui/excessive_precision.fixed
@@ -4,9 +4,16 @@
     overflowing_literals,
     unused_variables,
     clippy::print_literal,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::approx_constant
 )]
 
+macro_rules! make_pi {
+    ($i:ident : $t:ty) => {
+        const $i: $t = 3.14159265358979323846264338327950288419716939937510582097494459230781640628;
+    };
+}
+
 fn main() {
     // Consts
     const GOOD32: f32 = 0.123_456;
@@ -101,4 +108,40 @@ fn main() {
     const _: f64 = 3.0;
     //~^ excessive_precision
     const _: f64 = 3.0000000000000000;
+
+    // Overly specified constants
+    let _: f32 = 1.012_345_7;
+    //~^ excessive_precision
+    let _: f64 = 1.012_345_678_901_234_6;
+    //~^ excessive_precision
+    const _: f32 = 1.01234567890123456789012345678901234567890;
+    const _: f64 = 1.01234567890123456789012345678901234567890;
+
+    static STATIC1: f32 = 1.01234567890123456789012345678901234567890;
+    static STATIC2: f64 = 1.01234567890123456789012345678901234567890;
+
+    static mut STATIC_MUT1: f32 = 1.01234567890123456789012345678901234567890;
+    static mut STATIC_MUT2: f64 = 1.01234567890123456789012345678901234567890;
+
+    // From issue #13855
+    let gamma = 0.577_215_664_901_532_9;
+    //~^ excessive_precision
+    const GAMMA: f64 = 0.5772156649015328606065120900824024310421;
+
+    make_pi!(P32: f32);
+    make_pi!(P64: f64);
+}
+
+trait ExcessivelyPreciseTrait {
+    // Overly specified constants
+    const GOOD1: f32 = 1.01234567890123456789012345678901234567890;
+    const GOOD2: f64 = 1.01234567890123456789012345678901234567890;
+}
+
+struct ExcessivelyPreciseStruct;
+
+impl ExcessivelyPreciseStruct {
+    // Overly specified constants
+    const GOOD1: f32 = 1.01234567890123456789012345678901234567890;
+    const GOOD2: f64 = 1.01234567890123456789012345678901234567890;
 }
diff --git a/src/tools/clippy/tests/ui/excessive_precision.rs b/src/tools/clippy/tests/ui/excessive_precision.rs
index 5dcf55cb927..7ee6247ee5a 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.rs
+++ b/src/tools/clippy/tests/ui/excessive_precision.rs
@@ -4,9 +4,16 @@
     overflowing_literals,
     unused_variables,
     clippy::print_literal,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::approx_constant
 )]
 
+macro_rules! make_pi {
+    ($i:ident : $t:ty) => {
+        const $i: $t = 3.14159265358979323846264338327950288419716939937510582097494459230781640628;
+    };
+}
+
 fn main() {
     // Consts
     const GOOD32: f32 = 0.123_456;
@@ -101,4 +108,40 @@ fn main() {
     const _: f64 = 3.0000000000000000e+00;
     //~^ excessive_precision
     const _: f64 = 3.0000000000000000;
+
+    // Overly specified constants
+    let _: f32 = 1.01234567890123456789012345678901234567890;
+    //~^ excessive_precision
+    let _: f64 = 1.01234567890123456789012345678901234567890;
+    //~^ excessive_precision
+    const _: f32 = 1.01234567890123456789012345678901234567890;
+    const _: f64 = 1.01234567890123456789012345678901234567890;
+
+    static STATIC1: f32 = 1.01234567890123456789012345678901234567890;
+    static STATIC2: f64 = 1.01234567890123456789012345678901234567890;
+
+    static mut STATIC_MUT1: f32 = 1.01234567890123456789012345678901234567890;
+    static mut STATIC_MUT2: f64 = 1.01234567890123456789012345678901234567890;
+
+    // From issue #13855
+    let gamma = 0.5772156649015328606065120900824024310421;
+    //~^ excessive_precision
+    const GAMMA: f64 = 0.5772156649015328606065120900824024310421;
+
+    make_pi!(P32: f32);
+    make_pi!(P64: f64);
+}
+
+trait ExcessivelyPreciseTrait {
+    // Overly specified constants
+    const GOOD1: f32 = 1.01234567890123456789012345678901234567890;
+    const GOOD2: f64 = 1.01234567890123456789012345678901234567890;
+}
+
+struct ExcessivelyPreciseStruct;
+
+impl ExcessivelyPreciseStruct {
+    // Overly specified constants
+    const GOOD1: f32 = 1.01234567890123456789012345678901234567890;
+    const GOOD2: f64 = 1.01234567890123456789012345678901234567890;
 }
diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr
index f5eeadf0c8c..40806d67487 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.stderr
+++ b/src/tools/clippy/tests/ui/excessive_precision.stderr
@@ -1,5 +1,5 @@
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:20:26
+  --> tests/ui/excessive_precision.rs:27:26
    |
 LL |     const BAD32_1: f32 = 0.123_456_789_f32;
    |                          ^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     const BAD32_1: f32 = 0.123_456_79_f32;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:22:26
+  --> tests/ui/excessive_precision.rs:29:26
    |
 LL |     const BAD32_2: f32 = 0.123_456_789;
    |                          ^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL +     const BAD32_2: f32 = 0.123_456_79;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:24:26
+  --> tests/ui/excessive_precision.rs:31:26
    |
 LL |     const BAD32_3: f32 = 0.100_000_000_000_1;
    |                          ^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL +     const BAD32_3: f32 = 0.1;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:26:29
+  --> tests/ui/excessive_precision.rs:33:29
    |
 LL |     const BAD32_EDGE: f32 = 1.000_000_9;
    |                             ^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL +     const BAD32_EDGE: f32 = 1.000_001;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:31:26
+  --> tests/ui/excessive_precision.rs:38:26
    |
 LL |     const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL +     const BAD64_3: f64 = 0.1;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:35:22
+  --> tests/ui/excessive_precision.rs:42:22
    |
 LL |     println!("{:?}", 8.888_888_888_888_888_888_888);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL +     println!("{:?}", 8.888_888_888_888_89);
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:47:22
+  --> tests/ui/excessive_precision.rs:54:22
    |
 LL |     let bad32: f32 = 1.123_456_789;
    |                      ^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL +     let bad32: f32 = 1.123_456_8;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:49:26
+  --> tests/ui/excessive_precision.rs:56:26
    |
 LL |     let bad32_suf: f32 = 1.123_456_789_f32;
    |                          ^^^^^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL +     let bad32_suf: f32 = 1.123_456_8_f32;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:51:21
+  --> tests/ui/excessive_precision.rs:58:21
    |
 LL |     let bad32_inf = 1.123_456_789_f32;
    |                     ^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL +     let bad32_inf = 1.123_456_8_f32;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:62:36
+  --> tests/ui/excessive_precision.rs:69:36
    |
 LL |     let bad_vec32: Vec<f32> = vec![0.123_456_789];
    |                                    ^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL +     let bad_vec32: Vec<f32> = vec![0.123_456_79];
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:64:36
+  --> tests/ui/excessive_precision.rs:71:36
    |
 LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL +     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_78];
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:69:24
+  --> tests/ui/excessive_precision.rs:76:24
    |
 LL |     let bad_e32: f32 = 1.123_456_788_888e-10;
    |                        ^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL +     let bad_e32: f32 = 1.123_456_8e-10;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:73:27
+  --> tests/ui/excessive_precision.rs:80:27
    |
 LL |     let bad_bige32: f32 = 1.123_456_788_888E-10;
    |                           ^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL +     let bad_bige32: f32 = 1.123_456_8E-10;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:86:13
+  --> tests/ui/excessive_precision.rs:93:13
    |
 LL |     let _ = 2.225_073_858_507_201_1e-308_f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL +     let _ = 2.225_073_858_507_201e-308_f64;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:90:13
+  --> tests/ui/excessive_precision.rs:97:13
    |
 LL |     let _ = 1.000_000_000_000_001e-324_f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL +     let _ = 0_f64;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:101:20
+  --> tests/ui/excessive_precision.rs:108:20
    |
 LL |     const _: f64 = 3.0000000000000000e+00;
    |                    ^^^^^^^^^^^^^^^^^^^^^^
@@ -192,5 +192,56 @@ LL -     const _: f64 = 3.0000000000000000e+00;
 LL +     const _: f64 = 3.0;
    |
 
-error: aborting due to 16 previous errors
+error: float has excessive precision
+  --> tests/ui/excessive_precision.rs:113:18
+   |
+LL |     let _: f32 = 1.01234567890123456789012345678901234567890;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider making it a `const` item
+  --> tests/ui/excessive_precision.rs:113:5
+   |
+LL |     let _: f32 = 1.01234567890123456789012345678901234567890;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the type or truncating it to
+   |
+LL -     let _: f32 = 1.01234567890123456789012345678901234567890;
+LL +     let _: f32 = 1.012_345_7;
+   |
+
+error: float has excessive precision
+  --> tests/ui/excessive_precision.rs:115:18
+   |
+LL |     let _: f64 = 1.01234567890123456789012345678901234567890;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider making it a `const` item
+  --> tests/ui/excessive_precision.rs:115:5
+   |
+LL |     let _: f64 = 1.01234567890123456789012345678901234567890;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the type or truncating it to
+   |
+LL -     let _: f64 = 1.01234567890123456789012345678901234567890;
+LL +     let _: f64 = 1.012_345_678_901_234_6;
+   |
+
+error: float has excessive precision
+  --> tests/ui/excessive_precision.rs:127:17
+   |
+LL |     let gamma = 0.5772156649015328606065120900824024310421;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider making it a `const` item
+  --> tests/ui/excessive_precision.rs:127:5
+   |
+LL |     let gamma = 0.5772156649015328606065120900824024310421;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the type or truncating it to
+   |
+LL -     let gamma = 0.5772156649015328606065120900824024310421;
+LL +     let gamma = 0.577_215_664_901_532_9;
+   |
+
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.rs b/src/tools/clippy/tests/ui/float_equality_without_abs.rs
index a1548db6710..e1dd7902683 100644
--- a/src/tools/clippy/tests/ui/float_equality_without_abs.rs
+++ b/src/tools/clippy/tests/ui/float_equality_without_abs.rs
@@ -1,8 +1,8 @@
+#![feature(f128)]
+#![feature(f16)]
 #![warn(clippy::float_equality_without_abs)]
 //@no-rustfix: suggestions cause type ambiguity
 
-// FIXME(f16_f128): add tests for these types when abs is available
-
 pub fn is_roughly_equal(a: f32, b: f32) -> bool {
     (a - b) < f32::EPSILON
     //~^ float_equality_without_abs
@@ -44,10 +44,20 @@ pub fn main() {
     let _ = f32::EPSILON > 1.0 - 2.0;
     //~^ float_equality_without_abs
 
+    let _ = (a as f16 - b as f16) < f16::EPSILON;
+    //~^ float_equality_without_abs
+
+    let _ = (a as f128 - b as f128) < f128::EPSILON;
+    //~^ float_equality_without_abs
+
     // those are correct
+    let _ = (a as f16 - b as f16).abs() < f16::EPSILON;
     let _ = (a - b).abs() < f32::EPSILON;
     let _ = (a as f64 - b as f64).abs() < f64::EPSILON;
+    let _ = (a as f128 - b as f128).abs() < f128::EPSILON;
 
+    let _ = f16::EPSILON > (a as f16 - b as f16).abs();
     let _ = f32::EPSILON > (a - b).abs();
     let _ = f64::EPSILON > (a as f64 - b as f64).abs();
+    let _ = f128::EPSILON > (a as f128 - b as f128).abs();
 }
diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr
index d4c89ce72ba..55a150dead5 100644
--- a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr
+++ b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr
@@ -89,5 +89,21 @@ LL |     let _ = f32::EPSILON > 1.0 - 2.0;
    |                            |
    |                            help: add `.abs()`: `(1.0 - 2.0).abs()`
 
-error: aborting due to 11 previous errors
+error: float equality check without `.abs()`
+  --> tests/ui/float_equality_without_abs.rs:47:13
+   |
+LL |     let _ = (a as f16 - b as f16) < f16::EPSILON;
+   |             ---------------------^^^^^^^^^^^^^^^
+   |             |
+   |             help: add `.abs()`: `(a as f16 - b as f16).abs()`
+
+error: float equality check without `.abs()`
+  --> tests/ui/float_equality_without_abs.rs:50:13
+   |
+LL |     let _ = (a as f128 - b as f128) < f128::EPSILON;
+   |             -----------------------^^^^^^^^^^^^^^^^
+   |             |
+   |             help: add `.abs()`: `(a as f128 - b as f128).abs()`
+
+error: aborting due to 13 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
index d14a805b666..0fd130609ae 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
@@ -165,3 +165,44 @@ mod issue15257 {
         do_something((i % 2 == 0).then_some(closure_fn));
     }
 }
+
+fn issue15005() {
+    struct Counter {
+        count: u32,
+    }
+
+    impl Counter {
+        fn new() -> Counter {
+            Counter { count: 0 }
+        }
+    }
+
+    impl Iterator for Counter {
+        type Item = u32;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            //~v if_then_some_else_none
+            (self.count < 5).then(||  { self.count += 1; self.count })
+        }
+    }
+}
+
+fn statements_from_macro() {
+    macro_rules! mac {
+        () => {
+            println!("foo");
+            println!("bar");
+        };
+    }
+    //~v if_then_some_else_none
+    let _ = true.then(||  { mac!(); 42 });
+}
+
+fn dont_lint_inside_macros() {
+    macro_rules! mac {
+        ($cond:expr, $res:expr) => {
+            if $cond { Some($res) } else { None }
+        };
+    }
+    let _: Option<u32> = mac!(true, 42);
+}
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 bb0072f3157..640828aa9bf 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
@@ -211,3 +211,54 @@ mod issue15257 {
         });
     }
 }
+
+fn issue15005() {
+    struct Counter {
+        count: u32,
+    }
+
+    impl Counter {
+        fn new() -> Counter {
+            Counter { count: 0 }
+        }
+    }
+
+    impl Iterator for Counter {
+        type Item = u32;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            //~v if_then_some_else_none
+            if self.count < 5 {
+                self.count += 1;
+                Some(self.count)
+            } else {
+                None
+            }
+        }
+    }
+}
+
+fn statements_from_macro() {
+    macro_rules! mac {
+        () => {
+            println!("foo");
+            println!("bar");
+        };
+    }
+    //~v if_then_some_else_none
+    let _ = if true {
+        mac!();
+        Some(42)
+    } else {
+        None
+    };
+}
+
+fn dont_lint_inside_macros() {
+    macro_rules! mac {
+        ($cond:expr, $res:expr) => {
+            if $cond { Some($res) } else { None }
+        };
+    }
+    let _: Option<u32> = mac!(true, 42);
+}
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 c2e624a0a73..58651a05594 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
@@ -116,5 +116,28 @@ LL | |             None
 LL | |         });
    | |_________^ help: try: `(i % 2 == 0).then_some(closure_fn)`
 
-error: aborting due to 11 previous errors
+error: this could be simplified with `bool::then`
+  --> tests/ui/if_then_some_else_none.rs:231:13
+   |
+LL | /             if self.count < 5 {
+LL | |                 self.count += 1;
+LL | |                 Some(self.count)
+LL | |             } else {
+LL | |                 None
+LL | |             }
+   | |_____________^ help: try: `(self.count < 5).then(||  { self.count += 1; self.count })`
+
+error: this could be simplified with `bool::then`
+  --> tests/ui/if_then_some_else_none.rs:249:13
+   |
+LL |       let _ = if true {
+   |  _____________^
+LL | |         mac!();
+LL | |         Some(42)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ help: try: `true.then(||  { mac!(); 42 })`
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs
index 9b8c3933197..7d01a7fb61f 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.rs
+++ b/src/tools/clippy/tests/ui/infinite_loops.rs
@@ -521,4 +521,19 @@ mod tokio_spawn_test {
     }
 }
 
+mod issue15541 {
+    async fn good() -> ! {
+        loop {
+            std::future::pending().await
+        }
+    }
+
+    async fn bad() {
+        //~v infinite_loop
+        loop {
+            std::future::pending().await
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr
index 4c6b6f725f1..319f1e5012b 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loops.stderr
@@ -333,5 +333,15 @@ LL | |             }
    |
    = help: if this is not intended, try adding a `break` or `return` condition in the loop
 
-error: aborting due to 23 previous errors
+error: infinite loop detected
+  --> tests/ui/infinite_loops.rs:533:9
+   |
+LL | /         loop {
+LL | |             std::future::pending().await
+LL | |         }
+   | |_________^
+   |
+   = help: if this is not intended, try adding a `break` or `return` condition in the loop
+
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
index 7b0d1906834..406336dbd09 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
@@ -108,6 +108,8 @@ fn generics() {
     //~^ manual_is_ascii_check
     take_while(|c: char| c.is_ascii_uppercase());
     //~^ manual_is_ascii_check
+    take_while(|c: char| c.is_ascii_uppercase());
+    //~^ manual_is_ascii_check
 }
 
 fn adds_type_reference() {
@@ -115,4 +117,6 @@ fn adds_type_reference() {
     //~^ manual_is_ascii_check
     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
     //~^ manual_is_ascii_check
+    let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
+    //~^ manual_is_ascii_check
 }
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
index e4f7fe9f583..a624497e75e 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
@@ -108,6 +108,8 @@ fn generics() {
     //~^ manual_is_ascii_check
     take_while(|c: char| ('A'..='Z').contains(&c));
     //~^ manual_is_ascii_check
+    take_while(|c| matches!(c, 'A'..='Z'));
+    //~^ manual_is_ascii_check
 }
 
 fn adds_type_reference() {
@@ -115,4 +117,6 @@ fn adds_type_reference() {
     //~^ manual_is_ascii_check
     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect();
     //~^ manual_is_ascii_check
+    let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| matches!(c, '0'..='9')).collect();
+    //~^ manual_is_ascii_check
 }
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
index 9fd7f457b42..cb2548ea731 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
@@ -176,7 +176,19 @@ LL |     take_while(|c: char| ('A'..='Z').contains(&c));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> tests/ui/manual_is_ascii_check.rs:114:63
+  --> tests/ui/manual_is_ascii_check.rs:111:20
+   |
+LL |     take_while(|c| matches!(c, 'A'..='Z'));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -     take_while(|c| matches!(c, 'A'..='Z'));
+LL +     take_while(|c: char| c.is_ascii_uppercase());
+   |
+
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:116:63
    |
 LL |     let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect();
    |                                                               ^^^^^^^^^^^^^^^^^^^^^^^
@@ -188,7 +200,7 @@ LL +     let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_
    |
 
 error: manual check for common ascii range
-  --> tests/ui/manual_is_ascii_check.rs:116:71
+  --> tests/ui/manual_is_ascii_check.rs:118:71
    |
 LL |     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect();
    |                                                                       ^^^^^^^^^^^^^^^^^^^^^^^
@@ -199,5 +211,17 @@ LL -     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'.
 LL +     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
    |
 
-error: aborting due to 29 previous errors
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:120:71
+   |
+LL |     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| matches!(c, '0'..='9')).collect();
+   |                                                                       ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| matches!(c, '0'..='9')).collect();
+LL +     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
+   |
+
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed
index 6c971ba6338..a10aae8cc12 100644
--- a/src/tools/clippy/tests/ui/map_identity.fixed
+++ b/src/tools/clippy/tests/ui/map_identity.fixed
@@ -1,3 +1,4 @@
+//@require-annotations-for-level: ERROR
 #![warn(clippy::map_identity)]
 #![allow(clippy::needless_return, clippy::disallowed_names)]
 
@@ -72,20 +73,33 @@ fn issue11764() {
 }
 
 fn issue13904() {
-    // don't lint: `it.next()` would not be legal as `it` is immutable
-    let it = [1, 2, 3].into_iter();
-    let _ = it.map(|x| x).next();
+    // lint, but there's a catch:
+    // when we remove the `.map()`, `it.next()` would require `it` to be mutable
+    // therefore, include that in the suggestion as well
+    let mut it = [1, 2, 3].into_iter();
+    let _ = it.next();
+    //~^ map_identity
+    //~| HELP: remove the call to `map`, and make `it` mutable
+
+    // lint
+    let mut index = [1, 2, 3].into_iter();
+    let mut subindex = (index.by_ref().take(3), 42);
+    let _ = subindex.0.next();
+    //~^ map_identity
+    //~| HELP: remove the call to `map`, and make `subindex` mutable
 
     // lint
     #[allow(unused_mut)]
     let mut it = [1, 2, 3].into_iter();
     let _ = it.next();
     //~^ map_identity
+    //~| HELP: remove the call to `map`
 
     // lint
     let it = [1, 2, 3].into_iter();
     let _ = { it }.next();
     //~^ map_identity
+    //~| HELP: remove the call to `map`
 }
 
 // same as `issue11764`, but for arrays
diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs
index 59dcfcda3b6..fc6e018f924 100644
--- a/src/tools/clippy/tests/ui/map_identity.rs
+++ b/src/tools/clippy/tests/ui/map_identity.rs
@@ -1,3 +1,4 @@
+//@require-annotations-for-level: ERROR
 #![warn(clippy::map_identity)]
 #![allow(clippy::needless_return, clippy::disallowed_names)]
 
@@ -78,20 +79,33 @@ fn issue11764() {
 }
 
 fn issue13904() {
-    // don't lint: `it.next()` would not be legal as `it` is immutable
+    // lint, but there's a catch:
+    // when we remove the `.map()`, `it.next()` would require `it` to be mutable
+    // therefore, include that in the suggestion as well
     let it = [1, 2, 3].into_iter();
     let _ = it.map(|x| x).next();
+    //~^ map_identity
+    //~| HELP: remove the call to `map`, and make `it` mutable
+
+    // lint
+    let mut index = [1, 2, 3].into_iter();
+    let subindex = (index.by_ref().take(3), 42);
+    let _ = subindex.0.map(|n| n).next();
+    //~^ map_identity
+    //~| HELP: remove the call to `map`, and make `subindex` mutable
 
     // lint
     #[allow(unused_mut)]
     let mut it = [1, 2, 3].into_iter();
     let _ = it.map(|x| x).next();
     //~^ map_identity
+    //~| HELP: remove the call to `map`
 
     // lint
     let it = [1, 2, 3].into_iter();
     let _ = { it }.map(|x| x).next();
     //~^ map_identity
+    //~| HELP: remove the call to `map`
 }
 
 // same as `issue11764`, but for arrays
diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr
index a50c0d6b87b..8d19d62cdc6 100644
--- a/src/tools/clippy/tests/ui/map_identity.stderr
+++ b/src/tools/clippy/tests/ui/map_identity.stderr
@@ -1,5 +1,5 @@
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:7:47
+  --> tests/ui/map_identity.rs:8:47
    |
 LL |     let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
    |                                               ^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
@@ -8,25 +8,25 @@ LL |     let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
    = help: to override `-D warnings` add `#[allow(clippy::map_identity)]`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:9:57
+  --> tests/ui/map_identity.rs:10:57
    |
 LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
    |                                                         ^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:9:29
+  --> tests/ui/map_identity.rs:10:29
    |
 LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:12:32
+  --> tests/ui/map_identity.rs:13:32
    |
 LL |     let _: Option<u8> = Some(3).map(|x| x);
    |                                ^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:14:36
+  --> tests/ui/map_identity.rs:15:36
    |
 LL |       let _: Result<i8, f32> = Ok(-3).map(|x| {
    |  ____________________________________^
@@ -36,19 +36,19 @@ LL | |     });
    | |______^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:25:36
+  --> tests/ui/map_identity.rs:26:36
    |
 LL |     let _: Result<u32, u32> = Ok(1).map_err(|a| a);
    |                                    ^^^^^^^^^^^^^^^ help: remove the call to `map_err`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:36:22
+  --> tests/ui/map_identity.rs:37:22
    |
 LL |     let _ = x.clone().map(|(x, y)| (x, y));
    |                      ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:38:22
+  --> tests/ui/map_identity.rs:39:22
    |
 LL |       let _ = x.clone().map(|(x, y)| {
    |  ______________________^
@@ -58,76 +58,100 @@ LL | |     });
    | |______^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:42:22
+  --> tests/ui/map_identity.rs:43:22
    |
 LL |     let _ = x.clone().map(|(x, y)| return (x, y));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:46:22
+  --> tests/ui/map_identity.rs:47:22
    |
 LL |     let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:76:30
+  --> tests/ui/map_identity.rs:77:30
    |
 LL |     let _ = x.iter().copied().map(|(x, y)| (x, y));
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:88:15
+  --> tests/ui/map_identity.rs:86:15
+   |
+LL |     let _ = it.map(|x| x).next();
+   |               ^^^^^^^^^^^
+   |
+help: remove the call to `map`, and make `it` mutable
+   |
+LL ~     let mut it = [1, 2, 3].into_iter();
+LL ~     let _ = it.next();
+   |
+
+error: unnecessary map of the identity function
+  --> tests/ui/map_identity.rs:93:23
+   |
+LL |     let _ = subindex.0.map(|n| n).next();
+   |                       ^^^^^^^^^^^
+   |
+help: remove the call to `map`, and make `subindex` mutable
+   |
+LL ~     let mut subindex = (index.by_ref().take(3), 42);
+LL ~     let _ = subindex.0.next();
+   |
+
+error: unnecessary map of the identity function
+  --> tests/ui/map_identity.rs:100:15
    |
 LL |     let _ = it.map(|x| x).next();
    |               ^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:93:19
+  --> tests/ui/map_identity.rs:106:19
    |
 LL |     let _ = { it }.map(|x| x).next();
    |                   ^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:105:30
+  --> tests/ui/map_identity.rs:119:30
    |
 LL |     let _ = x.iter().copied().map(|[x, y]| [x, y]);
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:131:26
+  --> tests/ui/map_identity.rs:145:26
    |
 LL |     let _ = x.into_iter().map(|Foo { foo, bar }| Foo { foo, bar });
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:135:26
+  --> tests/ui/map_identity.rs:149:26
    |
 LL |     let _ = x.into_iter().map(|Foo { foo, bar }| foo::Foo { foo, bar });
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:143:26
+  --> tests/ui/map_identity.rs:157:26
    |
 LL |     let _ = x.into_iter().map(|Foo { foo, bar }| Foo { foo: foo, bar: bar });
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:147:26
+  --> tests/ui/map_identity.rs:161:26
    |
 LL |     let _ = x.into_iter().map(|Foo { foo, bar }| Foo { bar, foo });
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:157:26
+  --> tests/ui/map_identity.rs:171:26
    |
 LL |     let _ = x.into_iter().map(|Foo2(foo, bar)| Foo2(foo, bar));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> tests/ui/map_identity.rs:161:26
+  --> tests/ui/map_identity.rs:175:26
    |
 LL |     let _ = x.into_iter().map(|Foo2(foo, bar)| foo::Foo2(foo, bar));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
-error: aborting due to 20 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_inline.rs b/src/tools/clippy/tests/ui/missing_inline.rs
index 223c7447975..8e937d60951 100644
--- a/src/tools/clippy/tests/ui/missing_inline.rs
+++ b/src/tools/clippy/tests/ui/missing_inline.rs
@@ -97,3 +97,10 @@ pub mod issue15301 {
         println!("Just called a Rust function from Rust!");
     }
 }
+
+pub mod issue15491 {
+    pub trait Foo {
+        #[allow(clippy::missing_inline_in_public_items)]
+        fn foo(&self) {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.rs b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.rs
new file mode 100644
index 00000000000..08ba3b791ee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.rs
@@ -0,0 +1,29 @@
+//@no-rustfix
+
+fn issue14984() {
+    async fn e() {}
+    async fn x() -> u32 {
+        0
+    }
+    async fn y() -> f32 {
+        0.0
+    };
+    let mut yy = unsafe { std::ptr::read(&y()) };
+    yy = unsafe { std::mem::transmute(std::ptr::read(&x())) };
+    //~^ missing_transmute_annotations
+
+    let mut zz = 0u8;
+    zz = unsafe { std::mem::transmute(std::ptr::read(&x())) };
+    //~^ missing_transmute_annotations
+
+    yy = unsafe { std::mem::transmute(zz) };
+    //~^ missing_transmute_annotations
+
+    fn a() -> impl Sized {
+        0u32
+    }
+
+    let mut b: f32 = 0.0;
+    b = unsafe { std::mem::transmute(a()) };
+    //~^ missing_transmute_annotations
+}
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.stderr b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.stderr
new file mode 100644
index 00000000000..83efdce13f7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.stderr
@@ -0,0 +1,36 @@
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations_unfixable.rs:12:29
+   |
+LL |     yy = unsafe { std::mem::transmute(std::ptr::read(&x())) };
+   |                             ^^^^^^^^^
+   |
+   = help: consider giving the source and destination types a name, and adding missing type annotations
+   = note: `-D clippy::missing-transmute-annotations` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_transmute_annotations)]`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations_unfixable.rs:16:29
+   |
+LL |     zz = unsafe { std::mem::transmute(std::ptr::read(&x())) };
+   |                             ^^^^^^^^^
+   |
+   = help: consider giving the origin type a name, and adding missing type annotations
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations_unfixable.rs:19:29
+   |
+LL |     yy = unsafe { std::mem::transmute(zz) };
+   |                             ^^^^^^^^^
+   |
+   = help: consider giving the destination type a name, and adding missing type annotations
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations_unfixable.rs:27:28
+   |
+LL |     b = unsafe { std::mem::transmute(a()) };
+   |                            ^^^^^^^^^
+   |
+   = help: consider giving `a()`'s type a name, and adding missing type annotations
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_reference.fixed b/src/tools/clippy/tests/ui/mut_reference.fixed
new file mode 100644
index 00000000000..03d854099e6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_reference.fixed
@@ -0,0 +1,170 @@
+#![allow(clippy::mut_mut)]
+
+fn takes_ref(a: &i32) {}
+fn takes_refmut(a: &mut i32) {}
+fn takes_ref_ref(a: &&i32) {}
+fn takes_refmut_ref(a: &mut &i32) {}
+fn takes_ref_refmut(a: &&mut i32) {}
+fn takes_refmut_refmut(a: &mut &mut i32) {}
+fn takes_raw_const(a: *const i32) {}
+fn takes_raw_mut(a: *mut i32) {}
+
+mod issue11268 {
+    macro_rules! x {
+        (1 $f:expr) => {
+            $f(&mut 1);
+        };
+        (2 $f:expr) => {
+            $f(&mut &1)
+        };
+        (3 $f:expr) => {
+            $f(&mut &mut 1)
+        };
+        (4 $f:expr) => {
+            let mut a = 1;
+            $f(&raw mut a)
+        };
+    }
+
+    fn f() {
+        x!(1 super::takes_ref);
+        x!(1 super::takes_refmut);
+        x!(2 super::takes_refmut_ref);
+        x!(3 super::takes_ref_refmut);
+        x!(3 super::takes_refmut_refmut);
+        x!(4 super::takes_raw_const);
+        x!(4 super::takes_raw_mut);
+    }
+}
+
+struct MyStruct;
+
+impl MyStruct {
+    fn takes_ref(&self, a: &i32) {}
+    fn takes_refmut(&self, a: &mut i32) {}
+    fn takes_ref_ref(&self, a: &&i32) {}
+    fn takes_refmut_ref(&self, a: &mut &i32) {}
+    fn takes_ref_refmut(&self, a: &&mut i32) {}
+    fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
+    fn takes_raw_const(&self, a: *const i32) {}
+    fn takes_raw_mut(&self, a: *mut i32) {}
+}
+
+#[warn(clippy::unnecessary_mut_passed)]
+fn main() {
+    // Functions
+    takes_ref(&42);
+    //~^ unnecessary_mut_passed
+    takes_ref_ref(&&42);
+    //~^ unnecessary_mut_passed
+    takes_ref_refmut(&&mut 42);
+    //~^ unnecessary_mut_passed
+    takes_raw_const(&42);
+    //~^ unnecessary_mut_passed
+
+    let as_ptr: fn(&i32) = takes_ref;
+    as_ptr(&42);
+    //~^ unnecessary_mut_passed
+    let as_ptr: fn(&&i32) = takes_ref_ref;
+    as_ptr(&&42);
+    //~^ unnecessary_mut_passed
+    let as_ptr: fn(&&mut i32) = takes_ref_refmut;
+    as_ptr(&&mut 42);
+    //~^ unnecessary_mut_passed
+    let as_ptr: fn(*const i32) = takes_raw_const;
+    as_ptr(&42);
+    //~^ unnecessary_mut_passed
+
+    // Methods
+    let my_struct = MyStruct;
+    my_struct.takes_ref(&42);
+    //~^ unnecessary_mut_passed
+    my_struct.takes_ref_ref(&&42);
+    //~^ unnecessary_mut_passed
+    my_struct.takes_ref_refmut(&&mut 42);
+    //~^ unnecessary_mut_passed
+    my_struct.takes_raw_const(&42);
+    //~^ unnecessary_mut_passed
+
+    // No error
+
+    // Functions
+    takes_ref(&42);
+    let as_ptr: fn(&i32) = takes_ref;
+    as_ptr(&42);
+
+    takes_refmut(&mut 42);
+    let as_ptr: fn(&mut i32) = takes_refmut;
+    as_ptr(&mut 42);
+
+    takes_ref_ref(&&42);
+    let as_ptr: fn(&&i32) = takes_ref_ref;
+    as_ptr(&&42);
+
+    takes_refmut_ref(&mut &42);
+    let as_ptr: fn(&mut &i32) = takes_refmut_ref;
+    as_ptr(&mut &42);
+
+    takes_ref_refmut(&&mut 42);
+    let as_ptr: fn(&&mut i32) = takes_ref_refmut;
+    as_ptr(&&mut 42);
+
+    takes_refmut_refmut(&mut &mut 42);
+    let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
+    as_ptr(&mut &mut 42);
+
+    takes_raw_const(&42);
+    let as_ptr: fn(*const i32) = takes_raw_const;
+    as_ptr(&42);
+
+    takes_raw_mut(&mut 42);
+    let as_ptr: fn(*mut i32) = takes_raw_mut;
+    as_ptr(&mut 42);
+
+    let a = &mut 42;
+    let b = &mut &42;
+    let c = &mut &mut 42;
+    takes_ref(a);
+    takes_ref_ref(b);
+    takes_ref_refmut(c);
+    takes_raw_const(a);
+
+    // Methods
+    my_struct.takes_ref(&42);
+    my_struct.takes_refmut(&mut 42);
+    my_struct.takes_ref_ref(&&42);
+    my_struct.takes_refmut_ref(&mut &42);
+    my_struct.takes_ref_refmut(&&mut 42);
+    my_struct.takes_refmut_refmut(&mut &mut 42);
+    my_struct.takes_raw_const(&42);
+    my_struct.takes_raw_mut(&mut 42);
+    my_struct.takes_ref(a);
+    my_struct.takes_ref_ref(b);
+    my_struct.takes_ref_refmut(c);
+    my_struct.takes_raw_const(a);
+    my_struct.takes_raw_mut(a);
+}
+
+// not supported currently
+fn raw_ptrs(my_struct: MyStruct) {
+    let mut n = 42;
+
+    takes_raw_const(&raw mut n);
+
+    let as_ptr: fn(*const i32) = takes_raw_const;
+    as_ptr(&raw mut n);
+
+    my_struct.takes_raw_const(&raw mut n);
+
+    // No error
+
+    takes_raw_const(&raw const n);
+    takes_raw_mut(&raw mut n);
+
+    let a = &raw mut n;
+    takes_raw_const(a);
+
+    my_struct.takes_raw_const(&raw const n);
+    my_struct.takes_raw_mut(&raw mut n);
+    my_struct.takes_raw_const(a);
+}
diff --git a/src/tools/clippy/tests/ui/mut_reference.rs b/src/tools/clippy/tests/ui/mut_reference.rs
index f664c373cdc..80e3f506927 100644
--- a/src/tools/clippy/tests/ui/mut_reference.rs
+++ b/src/tools/clippy/tests/ui/mut_reference.rs
@@ -1,60 +1,170 @@
-#![allow(unused_variables, dead_code)]
-//@no-rustfix
-fn takes_an_immutable_reference(a: &i32) {}
-fn takes_a_mutable_reference(a: &mut i32) {}
+#![allow(clippy::mut_mut)]
+
+fn takes_ref(a: &i32) {}
+fn takes_refmut(a: &mut i32) {}
+fn takes_ref_ref(a: &&i32) {}
+fn takes_refmut_ref(a: &mut &i32) {}
+fn takes_ref_refmut(a: &&mut i32) {}
+fn takes_refmut_refmut(a: &mut &mut i32) {}
+fn takes_raw_const(a: *const i32) {}
+fn takes_raw_mut(a: *mut i32) {}
 
 mod issue11268 {
     macro_rules! x {
-        ($f:expr) => {
+        (1 $f:expr) => {
             $f(&mut 1);
         };
+        (2 $f:expr) => {
+            $f(&mut &1)
+        };
+        (3 $f:expr) => {
+            $f(&mut &mut 1)
+        };
+        (4 $f:expr) => {
+            let mut a = 1;
+            $f(&raw mut a)
+        };
     }
 
     fn f() {
-        x!(super::takes_an_immutable_reference);
-        x!(super::takes_a_mutable_reference);
+        x!(1 super::takes_ref);
+        x!(1 super::takes_refmut);
+        x!(2 super::takes_refmut_ref);
+        x!(3 super::takes_ref_refmut);
+        x!(3 super::takes_refmut_refmut);
+        x!(4 super::takes_raw_const);
+        x!(4 super::takes_raw_mut);
     }
 }
 
 struct MyStruct;
 
 impl MyStruct {
-    fn takes_an_immutable_reference(&self, a: &i32) {}
-
-    fn takes_a_mutable_reference(&self, a: &mut i32) {}
+    fn takes_ref(&self, a: &i32) {}
+    fn takes_refmut(&self, a: &mut i32) {}
+    fn takes_ref_ref(&self, a: &&i32) {}
+    fn takes_refmut_ref(&self, a: &mut &i32) {}
+    fn takes_ref_refmut(&self, a: &&mut i32) {}
+    fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
+    fn takes_raw_const(&self, a: *const i32) {}
+    fn takes_raw_mut(&self, a: *mut i32) {}
 }
 
 #[warn(clippy::unnecessary_mut_passed)]
 fn main() {
     // Functions
-    takes_an_immutable_reference(&mut 42);
+    takes_ref(&mut 42);
+    //~^ unnecessary_mut_passed
+    takes_ref_ref(&mut &42);
+    //~^ unnecessary_mut_passed
+    takes_ref_refmut(&mut &mut 42);
+    //~^ unnecessary_mut_passed
+    takes_raw_const(&mut 42);
     //~^ unnecessary_mut_passed
 
-    let as_ptr: fn(&i32) = takes_an_immutable_reference;
+    let as_ptr: fn(&i32) = takes_ref;
+    as_ptr(&mut 42);
+    //~^ unnecessary_mut_passed
+    let as_ptr: fn(&&i32) = takes_ref_ref;
+    as_ptr(&mut &42);
+    //~^ unnecessary_mut_passed
+    let as_ptr: fn(&&mut i32) = takes_ref_refmut;
+    as_ptr(&mut &mut 42);
+    //~^ unnecessary_mut_passed
+    let as_ptr: fn(*const i32) = takes_raw_const;
     as_ptr(&mut 42);
     //~^ unnecessary_mut_passed
 
     // Methods
     let my_struct = MyStruct;
-    my_struct.takes_an_immutable_reference(&mut 42);
+    my_struct.takes_ref(&mut 42);
+    //~^ unnecessary_mut_passed
+    my_struct.takes_ref_ref(&mut &42);
+    //~^ unnecessary_mut_passed
+    my_struct.takes_ref_refmut(&mut &mut 42);
+    //~^ unnecessary_mut_passed
+    my_struct.takes_raw_const(&mut 42);
     //~^ unnecessary_mut_passed
 
     // No error
 
     // Functions
-    takes_an_immutable_reference(&42);
-    let as_ptr: fn(&i32) = takes_an_immutable_reference;
+    takes_ref(&42);
+    let as_ptr: fn(&i32) = takes_ref;
     as_ptr(&42);
 
-    takes_a_mutable_reference(&mut 42);
-    let as_ptr: fn(&mut i32) = takes_a_mutable_reference;
+    takes_refmut(&mut 42);
+    let as_ptr: fn(&mut i32) = takes_refmut;
+    as_ptr(&mut 42);
+
+    takes_ref_ref(&&42);
+    let as_ptr: fn(&&i32) = takes_ref_ref;
+    as_ptr(&&42);
+
+    takes_refmut_ref(&mut &42);
+    let as_ptr: fn(&mut &i32) = takes_refmut_ref;
+    as_ptr(&mut &42);
+
+    takes_ref_refmut(&&mut 42);
+    let as_ptr: fn(&&mut i32) = takes_ref_refmut;
+    as_ptr(&&mut 42);
+
+    takes_refmut_refmut(&mut &mut 42);
+    let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
+    as_ptr(&mut &mut 42);
+
+    takes_raw_const(&42);
+    let as_ptr: fn(*const i32) = takes_raw_const;
+    as_ptr(&42);
+
+    takes_raw_mut(&mut 42);
+    let as_ptr: fn(*mut i32) = takes_raw_mut;
     as_ptr(&mut 42);
 
     let a = &mut 42;
-    takes_an_immutable_reference(a);
+    let b = &mut &42;
+    let c = &mut &mut 42;
+    takes_ref(a);
+    takes_ref_ref(b);
+    takes_ref_refmut(c);
+    takes_raw_const(a);
 
     // Methods
-    my_struct.takes_an_immutable_reference(&42);
-    my_struct.takes_a_mutable_reference(&mut 42);
-    my_struct.takes_an_immutable_reference(a);
+    my_struct.takes_ref(&42);
+    my_struct.takes_refmut(&mut 42);
+    my_struct.takes_ref_ref(&&42);
+    my_struct.takes_refmut_ref(&mut &42);
+    my_struct.takes_ref_refmut(&&mut 42);
+    my_struct.takes_refmut_refmut(&mut &mut 42);
+    my_struct.takes_raw_const(&42);
+    my_struct.takes_raw_mut(&mut 42);
+    my_struct.takes_ref(a);
+    my_struct.takes_ref_ref(b);
+    my_struct.takes_ref_refmut(c);
+    my_struct.takes_raw_const(a);
+    my_struct.takes_raw_mut(a);
+}
+
+// not supported currently
+fn raw_ptrs(my_struct: MyStruct) {
+    let mut n = 42;
+
+    takes_raw_const(&raw mut n);
+
+    let as_ptr: fn(*const i32) = takes_raw_const;
+    as_ptr(&raw mut n);
+
+    my_struct.takes_raw_const(&raw mut n);
+
+    // No error
+
+    takes_raw_const(&raw const n);
+    takes_raw_mut(&raw mut n);
+
+    let a = &raw mut n;
+    takes_raw_const(a);
+
+    my_struct.takes_raw_const(&raw const n);
+    my_struct.takes_raw_mut(&raw mut n);
+    my_struct.takes_raw_const(a);
 }
diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr
index 474221329c2..5ecfaa37416 100644
--- a/src/tools/clippy/tests/ui/mut_reference.stderr
+++ b/src/tools/clippy/tests/ui/mut_reference.stderr
@@ -1,23 +1,77 @@
-error: the function `takes_an_immutable_reference` doesn't need a mutable reference
-  --> tests/ui/mut_reference.rs:30:34
+error: the function `takes_ref` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:56:15
    |
-LL |     takes_an_immutable_reference(&mut 42);
-   |                                  ^^^^^^^
+LL |     takes_ref(&mut 42);
+   |               ^^^^^^^ help: remove this `mut`: `&42`
    |
    = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]`
 
+error: the function `takes_ref_ref` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:58:19
+   |
+LL |     takes_ref_ref(&mut &42);
+   |                   ^^^^^^^^ help: remove this `mut`: `&&42`
+
+error: the function `takes_ref_refmut` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:60:22
+   |
+LL |     takes_ref_refmut(&mut &mut 42);
+   |                      ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
+
+error: the function `takes_raw_const` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:62:21
+   |
+LL |     takes_raw_const(&mut 42);
+   |                     ^^^^^^^ help: remove this `mut`: `&42`
+
+error: the function `as_ptr` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:66:12
+   |
+LL |     as_ptr(&mut 42);
+   |            ^^^^^^^ help: remove this `mut`: `&42`
+
+error: the function `as_ptr` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:69:12
+   |
+LL |     as_ptr(&mut &42);
+   |            ^^^^^^^^ help: remove this `mut`: `&&42`
+
+error: the function `as_ptr` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:72:12
+   |
+LL |     as_ptr(&mut &mut 42);
+   |            ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
+
 error: the function `as_ptr` doesn't need a mutable reference
-  --> tests/ui/mut_reference.rs:34:12
+  --> tests/ui/mut_reference.rs:75:12
    |
 LL |     as_ptr(&mut 42);
-   |            ^^^^^^^
+   |            ^^^^^^^ help: remove this `mut`: `&42`
+
+error: the method `takes_ref` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:80:25
+   |
+LL |     my_struct.takes_ref(&mut 42);
+   |                         ^^^^^^^ help: remove this `mut`: `&42`
+
+error: the method `takes_ref_ref` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:82:29
+   |
+LL |     my_struct.takes_ref_ref(&mut &42);
+   |                             ^^^^^^^^ help: remove this `mut`: `&&42`
+
+error: the method `takes_ref_refmut` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:84:32
+   |
+LL |     my_struct.takes_ref_refmut(&mut &mut 42);
+   |                                ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
 
-error: the method `takes_an_immutable_reference` doesn't need a mutable reference
-  --> tests/ui/mut_reference.rs:39:44
+error: the method `takes_raw_const` doesn't need a mutable reference
+  --> tests/ui/mut_reference.rs:86:31
    |
-LL |     my_struct.takes_an_immutable_reference(&mut 42);
-   |                                            ^^^^^^^
+LL |     my_struct.takes_raw_const(&mut 42);
+   |                               ^^^^^^^ help: remove this `mut`: `&42`
 
-error: aborting due to 3 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
index 3f117ee5a50..9404d07ba0e 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
@@ -135,7 +135,7 @@ error: equality checks against true are unnecessary
   --> tests/ui/needless_bool/fixable.rs:157:8
    |
 LL |     if x == true {};
-   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+   |        ^^^^^^^^^ help: try: `x`
    |
    = note: `-D clippy::bool-comparison` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
@@ -144,19 +144,19 @@ error: equality checks against false can be replaced by a negation
   --> tests/ui/needless_bool/fixable.rs:162:8
    |
 LL |     if x == false {};
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+   |        ^^^^^^^^^^ help: try: `!x`
 
 error: equality checks against true are unnecessary
   --> tests/ui/needless_bool/fixable.rs:173:8
    |
 LL |     if x == true {};
-   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+   |        ^^^^^^^^^ help: try: `x`
 
 error: equality checks against false can be replaced by a negation
   --> tests/ui/needless_bool/fixable.rs:175:8
    |
 LL |     if x == false {};
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+   |        ^^^^^^^^^^ help: try: `!x`
 
 error: this if-then-else expression returns a bool literal
   --> tests/ui/needless_bool/fixable.rs:185:12
diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
index 159cbe49828..24ce5786b91 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
@@ -1,6 +1,6 @@
 //@no-rustfix: overlapping suggestions
 #![warn(clippy::needless_for_each)]
-#![allow(clippy::needless_return, clippy::uninlined_format_args)]
+#![allow(clippy::needless_return)]
 
 fn main() {
     let v: Vec<i32> = Vec::new();
@@ -11,7 +11,22 @@ fn main() {
         if *v == 10 {
             return;
         } else {
-            println!("{}", v);
+            println!("{v}");
         }
     });
 }
+
+fn issue9912() {
+    let mut i = 0;
+    // Changing this to a `for` loop would break type inference
+    [].iter().for_each(move |_: &i32| {
+        //~^ needless_for_each
+        i += 1;
+    });
+
+    // Changing this would actually be okay, but we still suggest `MaybeIncorrect`ly
+    [1i32].iter().for_each(move |_: &i32| {
+        //~^ needless_for_each
+        i += 1;
+    });
+}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr
index 3a3a240c5a3..6bc56db68a0 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr
@@ -19,7 +19,7 @@ LL +
 LL +         if *v == 10 {
 LL +             return;
 LL +         } else {
-LL +             println!("{}", v);
+LL +             println!("{v}");
 LL +         }
 LL +     }
    |
@@ -29,5 +29,39 @@ LL -             return;
 LL +             continue;
    |
 
-error: aborting due to 1 previous error
+error: needless use of `for_each`
+  --> tests/ui/needless_for_each_unfixable.rs:22:5
+   |
+LL | /     [].iter().for_each(move |_: &i32| {
+LL | |
+LL | |         i += 1;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL ~     for _ in [].iter() {
+LL +
+LL +         i += 1;
+LL +     }
+   |
+
+error: needless use of `for_each`
+  --> tests/ui/needless_for_each_unfixable.rs:28:5
+   |
+LL | /     [1i32].iter().for_each(move |_: &i32| {
+LL | |
+LL | |         i += 1;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL ~     for _ in [1i32].iter() {
+LL +
+LL +         i += 1;
+LL +     }
+   |
+
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs
index 70cf9fa7369..ea4591d8b71 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.rs
+++ b/src/tools/clippy/tests/ui/needless_range_loop.rs
@@ -210,3 +210,35 @@ fn needless_loop() {
         black_box([1, 2, 3, 4, 5, 6, 7, 8][i]);
     }
 }
+
+fn issue_15068() {
+    let a = vec![vec![0u8; MAX_LEN]; MAX_LEN];
+    let b = vec![0u8; MAX_LEN];
+
+    for i in 0..MAX_LEN {
+        // no error
+        let _ = a[0][i];
+        let _ = b[i];
+    }
+
+    for i in 0..MAX_LEN {
+        // no error
+        let _ = a[i][0];
+        let _ = b[i];
+    }
+
+    for i in 0..MAX_LEN {
+        // no error
+        let _ = a[i][b[i] as usize];
+    }
+
+    for i in 0..MAX_LEN {
+        //~^ needless_range_loop
+        let _ = a[i][i];
+    }
+
+    for i in 0..MAX_LEN {
+        //~^ needless_range_loop
+        let _ = a[0][i];
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr
index 23c085f9d3b..33a519d8a80 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.stderr
+++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr
@@ -168,5 +168,29 @@ LL -     for i in 0..vec.len() {
 LL +     for (i, <item>) in vec.iter_mut().enumerate() {
    |
 
-error: aborting due to 14 previous errors
+error: the loop variable `i` is used to index `a`
+  --> tests/ui/needless_range_loop.rs:235:14
+   |
+LL |     for i in 0..MAX_LEN {
+   |              ^^^^^^^^^^
+   |
+help: consider using an iterator and enumerate()
+   |
+LL -     for i in 0..MAX_LEN {
+LL +     for (i, <item>) in a.iter().enumerate().take(MAX_LEN) {
+   |
+
+error: the loop variable `i` is only used to index `a`
+  --> tests/ui/needless_range_loop.rs:240:14
+   |
+LL |     for i in 0..MAX_LEN {
+   |              ^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL -     for i in 0..MAX_LEN {
+LL +     for <item> in a.iter().take(MAX_LEN) {
+   |
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index cacce9a7d1c..f03f74dfafe 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -182,14 +182,12 @@ fn issue_5794() {
     if !b == true {}
     //~^ nonminimal_bool
     //~| bool_comparison
-    //~| bool_comparison
     if !b != true {}
     //~^ nonminimal_bool
     //~| bool_comparison
     if true == !b {}
     //~^ nonminimal_bool
     //~| bool_comparison
-    //~| bool_comparison
     if true != !b {}
     //~^ nonminimal_bool
     //~| bool_comparison
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
index c20412974b2..6a20b9216da 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -154,98 +154,86 @@ error: this boolean expression can be simplified
 LL |     if !b == true {}
    |        ^^^^^^^^^^ help: try: `b != true`
 
-error: this comparison might be written more concisely
+error: equality checks against true are unnecessary
   --> tests/ui/nonminimal_bool.rs:182:8
    |
 LL |     if !b == true {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `b != true`
+   |        ^^^^^^^^^^ help: try: `!b`
    |
    = note: `-D clippy::bool-comparison` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
 
-error: equality checks against true are unnecessary
-  --> tests/ui/nonminimal_bool.rs:182:8
-   |
-LL |     if !b == true {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!b`
-
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:186:8
+  --> tests/ui/nonminimal_bool.rs:185:8
    |
 LL |     if !b != true {}
    |        ^^^^^^^^^^ help: try: `b == true`
 
 error: inequality checks against true can be replaced by a negation
-  --> tests/ui/nonminimal_bool.rs:186:8
+  --> tests/ui/nonminimal_bool.rs:185:8
    |
 LL |     if !b != true {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `b`
+   |        ^^^^^^^^^^ help: try: `b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:189:8
+  --> tests/ui/nonminimal_bool.rs:188:8
    |
 LL |     if true == !b {}
    |        ^^^^^^^^^^ help: try: `true != b`
 
-error: this comparison might be written more concisely
-  --> tests/ui/nonminimal_bool.rs:189:8
-   |
-LL |     if true == !b {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `true != b`
-
 error: equality checks against true are unnecessary
-  --> tests/ui/nonminimal_bool.rs:189:8
+  --> tests/ui/nonminimal_bool.rs:188:8
    |
 LL |     if true == !b {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!b`
+   |        ^^^^^^^^^^ help: try: `!b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:193:8
+  --> tests/ui/nonminimal_bool.rs:191:8
    |
 LL |     if true != !b {}
    |        ^^^^^^^^^^ help: try: `true == b`
 
 error: inequality checks against true can be replaced by a negation
-  --> tests/ui/nonminimal_bool.rs:193:8
+  --> tests/ui/nonminimal_bool.rs:191:8
    |
 LL |     if true != !b {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `b`
+   |        ^^^^^^^^^^ help: try: `b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:196:8
+  --> tests/ui/nonminimal_bool.rs:194:8
    |
 LL |     if !b == !c {}
    |        ^^^^^^^^ help: try: `b == c`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:198:8
+  --> tests/ui/nonminimal_bool.rs:196:8
    |
 LL |     if !b != !c {}
    |        ^^^^^^^^ help: try: `b != c`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:214:8
+  --> tests/ui/nonminimal_bool.rs:212:8
    |
 LL |     if !(a < 2.0 && !b) {
    |        ^^^^^^^^^^^^^^^^ help: try: `a >= 2.0 || b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:233:12
+  --> tests/ui/nonminimal_bool.rs:231:12
    |
 LL |         if !(matches!(ty, TyKind::Ref(_, _, _)) && !is_mutable(&expr)) {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!matches!(ty, TyKind::Ref(_, _, _)) || is_mutable(&expr)`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:253:8
+  --> tests/ui/nonminimal_bool.rs:251:8
    |
 LL |     if !S != true {}
    |        ^^^^^^^^^^ help: try: `S == true`
 
 error: inequality checks against true can be replaced by a negation
-  --> tests/ui/nonminimal_bool.rs:253:8
+  --> tests/ui/nonminimal_bool.rs:251:8
    |
 LL |     if !S != true {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!!S`
+   |        ^^^^^^^^^^ help: try: `!!S`
 
-error: aborting due to 33 previous errors
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
index 55c1b8f110c..340be7c7e93 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
@@ -102,4 +102,13 @@ fn option_map_unit_fn() {
     //~^ option_map_unit_fn
 }
 
+fn issue15568() {
+    unsafe fn f(_: u32) {}
+    let x = Some(3);
+    if let Some(x) = x { unsafe { f(x) } }
+    //~^ option_map_unit_fn
+    if let Some(x) = x { unsafe { f(x) } }
+    //~^ option_map_unit_fn
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
index 5ed47e4c60b..d902c87379b 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
@@ -102,4 +102,13 @@ fn option_map_unit_fn() {
     //~^ option_map_unit_fn
 }
 
+fn issue15568() {
+    unsafe fn f(_: u32) {}
+    let x = Some(3);
+    x.map(|x| unsafe { f(x) });
+    //~^ option_map_unit_fn
+    x.map(|x| unsafe { { f(x) } });
+    //~^ option_map_unit_fn
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
index 3f7abae34ee..2405aa9a7cc 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
@@ -153,5 +153,21 @@ LL |     option().map(|value| println!("{:?}", value));
    |     |
    |     help: try: `if let Some(value) = option() { println!("{:?}", value) }`
 
-error: aborting due to 19 previous errors
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
+  --> tests/ui/option_map_unit_fn_fixable.rs:108:5
+   |
+LL |     x.map(|x| unsafe { f(x) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try: `if let Some(x) = x { unsafe { f(x) } }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
+  --> tests/ui/option_map_unit_fn_fixable.rs:110:5
+   |
+LL |     x.map(|x| unsafe { { f(x) } });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try: `if let Some(x) = x { unsafe { f(x) } }`
+
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.fixed b/src/tools/clippy/tests/ui/or_then_unwrap.fixed
index ba9beef57af..9660b82fe7d 100644
--- a/src/tools/clippy/tests/ui/or_then_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/or_then_unwrap.fixed
@@ -28,6 +28,12 @@ fn main() {
     //
     //~^^ or_then_unwrap
 
+    // Call with macro should preserve the macro call rather than expand it
+    let option: Option<Vec<&str>> = None;
+    let _ = option.unwrap_or(vec!["fallback"]); // should trigger lint
+    //
+    //~^^ or_then_unwrap
+
     // as part of a method chain
     let option: Option<&str> = None;
     let _ = option.map(|v| v).unwrap_or("fallback").to_string().chars(); // should trigger lint
diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.rs b/src/tools/clippy/tests/ui/or_then_unwrap.rs
index fac90249a24..c3873352116 100644
--- a/src/tools/clippy/tests/ui/or_then_unwrap.rs
+++ b/src/tools/clippy/tests/ui/or_then_unwrap.rs
@@ -28,6 +28,12 @@ fn main() {
     //
     //~^^ or_then_unwrap
 
+    // Call with macro should preserve the macro call rather than expand it
+    let option: Option<Vec<&str>> = None;
+    let _ = option.or(Some(vec!["fallback"])).unwrap(); // should trigger lint
+    //
+    //~^^ or_then_unwrap
+
     // as part of a method chain
     let option: Option<&str> = None;
     let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint
diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.stderr b/src/tools/clippy/tests/ui/or_then_unwrap.stderr
index 1160498c605..3e66b15edbd 100644
--- a/src/tools/clippy/tests/ui/or_then_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/or_then_unwrap.stderr
@@ -14,10 +14,16 @@ LL |     let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger l
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")`
 
 error: found `.or(Some(…)).unwrap()`
-  --> tests/ui/or_then_unwrap.rs:33:31
+  --> tests/ui/or_then_unwrap.rs:33:20
+   |
+LL |     let _ = option.or(Some(vec!["fallback"])).unwrap(); // should trigger lint
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or(vec!["fallback"])`
+
+error: found `.or(Some(…)).unwrap()`
+  --> tests/ui/or_then_unwrap.rs:39:31
    |
 LL |     let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/panicking_macros.rs b/src/tools/clippy/tests/ui/panicking_macros.rs
index 65854d7eb4b..b044be7d54a 100644
--- a/src/tools/clippy/tests/ui/panicking_macros.rs
+++ b/src/tools/clippy/tests/ui/panicking_macros.rs
@@ -31,6 +31,20 @@ fn panic() {
     let b = a + 2;
 }
 
+const fn panic_const() {
+    let a = 2;
+    panic!();
+    //~^ panic
+
+    panic!("message");
+    //~^ panic
+
+    panic!("{} {}", "panic with", "multiple arguments");
+    //~^ panic
+
+    let b = a + 2;
+}
+
 fn todo() {
     let a = 2;
     todo!();
@@ -114,6 +128,7 @@ fn debug_assert_msg() {
 
 fn main() {
     panic();
+    panic_const();
     todo();
     unimplemented();
     unreachable();
diff --git a/src/tools/clippy/tests/ui/panicking_macros.stderr b/src/tools/clippy/tests/ui/panicking_macros.stderr
index 03e459e4ec6..7b767ae0f65 100644
--- a/src/tools/clippy/tests/ui/panicking_macros.stderr
+++ b/src/tools/clippy/tests/ui/panicking_macros.stderr
@@ -19,9 +19,27 @@ error: `panic` should not be present in production code
 LL |     panic!("{} {}", "panic with", "multiple arguments");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `todo` should not be present in production code
+error: `panic` should not be present in production code
   --> tests/ui/panicking_macros.rs:36:5
    |
+LL |     panic!();
+   |     ^^^^^^^^
+
+error: `panic` should not be present in production code
+  --> tests/ui/panicking_macros.rs:39:5
+   |
+LL |     panic!("message");
+   |     ^^^^^^^^^^^^^^^^^
+
+error: `panic` should not be present in production code
+  --> tests/ui/panicking_macros.rs:42:5
+   |
+LL |     panic!("{} {}", "panic with", "multiple arguments");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `todo` should not be present in production code
+  --> tests/ui/panicking_macros.rs:50:5
+   |
 LL |     todo!();
    |     ^^^^^^^
    |
@@ -29,19 +47,19 @@ LL |     todo!();
    = help: to override `-D warnings` add `#[allow(clippy::todo)]`
 
 error: `todo` should not be present in production code
-  --> tests/ui/panicking_macros.rs:39:5
+  --> tests/ui/panicking_macros.rs:53:5
    |
 LL |     todo!("message");
    |     ^^^^^^^^^^^^^^^^
 
 error: `todo` should not be present in production code
-  --> tests/ui/panicking_macros.rs:42:5
+  --> tests/ui/panicking_macros.rs:56:5
    |
 LL |     todo!("{} {}", "panic with", "multiple arguments");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `unimplemented` should not be present in production code
-  --> tests/ui/panicking_macros.rs:50:5
+  --> tests/ui/panicking_macros.rs:64:5
    |
 LL |     unimplemented!();
    |     ^^^^^^^^^^^^^^^^
@@ -50,19 +68,19 @@ LL |     unimplemented!();
    = help: to override `-D warnings` add `#[allow(clippy::unimplemented)]`
 
 error: `unimplemented` should not be present in production code
-  --> tests/ui/panicking_macros.rs:53:5
+  --> tests/ui/panicking_macros.rs:67:5
    |
 LL |     unimplemented!("message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `unimplemented` should not be present in production code
-  --> tests/ui/panicking_macros.rs:56:5
+  --> tests/ui/panicking_macros.rs:70:5
    |
 LL |     unimplemented!("{} {}", "panic with", "multiple arguments");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: usage of the `unreachable!` macro
-  --> tests/ui/panicking_macros.rs:64:5
+  --> tests/ui/panicking_macros.rs:78:5
    |
 LL |     unreachable!();
    |     ^^^^^^^^^^^^^^
@@ -71,40 +89,40 @@ LL |     unreachable!();
    = help: to override `-D warnings` add `#[allow(clippy::unreachable)]`
 
 error: usage of the `unreachable!` macro
-  --> tests/ui/panicking_macros.rs:67:5
+  --> tests/ui/panicking_macros.rs:81:5
    |
 LL |     unreachable!("message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: usage of the `unreachable!` macro
-  --> tests/ui/panicking_macros.rs:70:5
+  --> tests/ui/panicking_macros.rs:84:5
    |
 LL |     unreachable!("{} {}", "panic with", "multiple arguments");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `panic` should not be present in production code
-  --> tests/ui/panicking_macros.rs:78:5
+  --> tests/ui/panicking_macros.rs:92:5
    |
 LL |     panic!();
    |     ^^^^^^^^
 
 error: `todo` should not be present in production code
-  --> tests/ui/panicking_macros.rs:81:5
+  --> tests/ui/panicking_macros.rs:95:5
    |
 LL |     todo!();
    |     ^^^^^^^
 
 error: `unimplemented` should not be present in production code
-  --> tests/ui/panicking_macros.rs:84:5
+  --> tests/ui/panicking_macros.rs:98:5
    |
 LL |     unimplemented!();
    |     ^^^^^^^^^^^^^^^^
 
 error: usage of the `unreachable!` macro
-  --> tests/ui/panicking_macros.rs:87:5
+  --> tests/ui/panicking_macros.rs:101:5
    |
 LL |     unreachable!();
    |     ^^^^^^^^^^^^^^
 
-error: aborting due to 16 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed
index ebfe19c700e..26139f9b671 100644
--- a/src/tools/clippy/tests/ui/print_literal.fixed
+++ b/src/tools/clippy/tests/ui/print_literal.fixed
@@ -105,3 +105,16 @@ fn issue_14930() {
     println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
     //~^ print_literal
 }
+
+fn issue_15576() {
+    println!("Hello x is {1:.*}", 5, 0.01);
+    //~^ print_literal
+
+    println!("Hello x is {:.p$}", 0.01, p = 5);
+    //~^ print_literal
+
+    println!(
+        "Hello name: x is {1:.*} (which {1} with {0} places)", 5, 0.01
+    );
+    //~^^ print_literal
+}
diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs
index 8f3d9be0698..7c4cf028e84 100644
--- a/src/tools/clippy/tests/ui/print_literal.rs
+++ b/src/tools/clippy/tests/ui/print_literal.rs
@@ -106,3 +106,17 @@ fn issue_14930() {
     println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
     //~^ print_literal
 }
+
+fn issue_15576() {
+    println!("Hello {} is {2:.*}", "x", 5, 0.01);
+    //~^ print_literal
+
+    println!("Hello {} is {:.p$}", "x", 0.01, p = 5);
+    //~^ print_literal
+
+    println!(
+        "Hello {}: {2} is {3:.*} (which {3} with {1} places)",
+        "name", 5, "x", 0.01
+    );
+    //~^^ print_literal
+}
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr
index 1c378017d15..c136f52800f 100644
--- a/src/tools/clippy/tests/ui/print_literal.stderr
+++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -277,5 +277,41 @@ LL -     println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
 LL +     println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
    |
 
-error: aborting due to 22 previous errors
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:111:36
+   |
+LL |     println!("Hello {} is {2:.*}", "x", 5, 0.01);
+   |                                    ^^^
+   |
+help: try
+   |
+LL -     println!("Hello {} is {2:.*}", "x", 5, 0.01);
+LL +     println!("Hello x is {1:.*}", 5, 0.01);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:114:36
+   |
+LL |     println!("Hello {} is {:.p$}", "x", 0.01, p = 5);
+   |                                    ^^^
+   |
+help: try
+   |
+LL -     println!("Hello {} is {:.p$}", "x", 0.01, p = 5);
+LL +     println!("Hello x is {:.p$}", 0.01, p = 5);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:119:9
+   |
+LL |         "name", 5, "x", 0.01
+   |         ^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         "Hello {}: {2} is {3:.*} (which {3} with {1} places)",
+LL +         "Hello name: x is {1:.*} (which {1} with {0} places)", 5, 0.01
+   |
+
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
index 78e1ceb480a..4457878b6fa 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
@@ -229,3 +229,9 @@ fn issue15283() {
         //~^ ptr_as_ptr
     }
 }
+
+fn issue15232() {
+    let mut b = Box::new(0i32);
+    let _ptr = std::ptr::addr_of_mut!(*b).cast::<()>();
+    //~^ ptr_as_ptr
+}
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
index 70732cf0a6c..9124fc912d2 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
@@ -229,3 +229,9 @@ fn issue15283() {
         //~^ ptr_as_ptr
     }
 }
+
+fn issue15232() {
+    let mut b = Box::new(0i32);
+    let _ptr = std::ptr::addr_of_mut!(*b) as *mut ();
+    //~^ ptr_as_ptr
+}
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
index c0a2a4b6d20..af21c1e35f5 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -199,5 +199,11 @@ error: `as` casting between raw pointers without changing their constness
 LL |         let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8);
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u8>()`
 
-error: aborting due to 33 previous errors
+error: `as` casting between raw pointers without changing their constness
+  --> tests/ui/ptr_as_ptr.rs:235:16
+   |
+LL |     let _ptr = std::ptr::addr_of_mut!(*b) as *mut ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `std::ptr::addr_of_mut!(*b).cast::<()>()`
+
+error: aborting due to 34 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
index 79bfae1f7eb..cf57de53d9f 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
@@ -106,3 +106,9 @@ fn issue14621() {
     let _ = std::ptr::addr_of_mut!(local).cast_const();
     //~^ ptr_cast_constness
 }
+
+fn issue11317() {
+    let r = &0_u32;
+    let _ptr: *mut u32 = (r as *const u32).cast_mut();
+    //~^ ptr_cast_constness
+}
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
index f6590dabd5b..ea53a0fa8c5 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.rs
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
@@ -106,3 +106,9 @@ fn issue14621() {
     let _ = std::ptr::addr_of_mut!(local) as *const _;
     //~^ ptr_cast_constness
 }
+
+fn issue11317() {
+    let r = &0_u32;
+    let _ptr: *mut u32 = r as *const _ as *mut _;
+    //~^ ptr_cast_constness
+}
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
index 0b1644168ff..4adb5cc5ad7 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
@@ -89,5 +89,11 @@ error: `as` casting between raw pointers while changing only its constness
 LL |     let _ = std::ptr::addr_of_mut!(local) as *const _;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `std::ptr::addr_of_mut!(local).cast_const()`
 
-error: aborting due to 14 previous errors
+error: `as` casting between raw pointers while changing only its constness
+  --> tests/ui/ptr_cast_constness.rs:112:26
+   |
+LL |     let _ptr: *mut u32 = r as *const _ as *mut _;
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(r as *const u32).cast_mut()`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
index 7eb53e733ad..7308e78aae2 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
@@ -86,3 +86,8 @@ fn main() {
 
     unit_fn_block()
 }
+
+pub fn issue15388() {
+    #[rustfmt::skip]
+    {0; 0};
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
index 9fa5b117194..467bf4d779f 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
@@ -86,3 +86,8 @@ fn main() {
 
     unit_fn_block()
 }
+
+pub fn issue15388() {
+    #[rustfmt::skip]
+    {0; 0};
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.fixed
new file mode 100644
index 00000000000..5b93a91da00
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.fixed
@@ -0,0 +1,11 @@
+// Test when the feature `stmt_expr_attributes` is enabled
+
+#![feature(stmt_expr_attributes)]
+#![allow(clippy::no_effect)]
+#![warn(clippy::semicolon_inside_block)]
+
+pub fn issue15388() {
+    #[rustfmt::skip]
+    {0; 0;}
+    //~^ semicolon_inside_block
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.rs b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.rs
new file mode 100644
index 00000000000..aa2c0cb5029
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.rs
@@ -0,0 +1,11 @@
+// Test when the feature `stmt_expr_attributes` is enabled
+
+#![feature(stmt_expr_attributes)]
+#![allow(clippy::no_effect)]
+#![warn(clippy::semicolon_inside_block)]
+
+pub fn issue15388() {
+    #[rustfmt::skip]
+    {0; 0};
+    //~^ semicolon_inside_block
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.stderr
new file mode 100644
index 00000000000..5bb91915a5f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.stderr
@@ -0,0 +1,16 @@
+error: consider moving the `;` inside the block for consistent formatting
+  --> tests/ui/semicolon_inside_block_stmt_expr_attrs.rs:9:5
+   |
+LL |     {0; 0};
+   |     ^^^^^^^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::semicolon_inside_block)]`
+help: put the `;` here
+   |
+LL -     {0; 0};
+LL +     {0; 0;}
+   |
+
+error: aborting due to 1 previous error
+
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 603ab0accb0..c27cec55824 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -89,3 +89,10 @@ fn msrv_1_76(_: std::net::IpAddr) {}
 #[clippy::msrv = "1.77"]
 fn msrv_1_77(_: core::net::IpAddr) {}
 //~^ std_instead_of_core
+
+#[warn(clippy::alloc_instead_of_core)]
+fn issue15579() {
+    use std::alloc;
+
+    let layout = alloc::Layout::new::<u8>();
+}
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 b6d4abad9f8..7d53f7fc307 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -89,3 +89,10 @@ fn msrv_1_76(_: std::net::IpAddr) {}
 #[clippy::msrv = "1.77"]
 fn msrv_1_77(_: std::net::IpAddr) {}
 //~^ std_instead_of_core
+
+#[warn(clippy::alloc_instead_of_core)]
+fn issue15579() {
+    use std::alloc;
+
+    let layout = alloc::Layout::new::<u8>();
+}
diff --git a/src/tools/clippy/tests/ui/unit_cmp.rs b/src/tools/clippy/tests/ui/unit_cmp.rs
index 93f5b87c3d2..0a0fe3a1990 100644
--- a/src/tools/clippy/tests/ui/unit_cmp.rs
+++ b/src/tools/clippy/tests/ui/unit_cmp.rs
@@ -68,3 +68,20 @@ fn main() {
         }
     );
 }
+
+fn issue15559() {
+    fn foo() {}
+    assert_eq!(
+        //~^ unit_cmp
+        {
+            1;
+        },
+        foo()
+    );
+    assert_eq!(foo(), foo());
+    //~^ unit_cmp
+
+    // don't lint on explicitly written unit expr
+    assert_eq!(foo(), ());
+    assert_ne!((), ContainsUnit(()).0);
+}
diff --git a/src/tools/clippy/tests/ui/unit_cmp.stderr b/src/tools/clippy/tests/ui/unit_cmp.stderr
index 8f26749fd86..21aa9dce151 100644
--- a/src/tools/clippy/tests/ui/unit_cmp.stderr
+++ b/src/tools/clippy/tests/ui/unit_cmp.stderr
@@ -71,5 +71,23 @@ LL | |             true;
 LL | |     );
    | |_____^
 
-error: aborting due to 6 previous errors
+error: `assert_eq` of unit values detected. This will always succeed
+  --> tests/ui/unit_cmp.rs:74:5
+   |
+LL | /     assert_eq!(
+LL | |
+LL | |         {
+LL | |             1;
+LL | |         },
+LL | |         foo()
+LL | |     );
+   | |_____^
+
+error: `assert_eq` of unit values detected. This will always succeed
+  --> tests/ui/unit_cmp.rs:81:5
+   |
+LL |     assert_eq!(foo(), foo());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
index a4fdf09cd5d..17518e123d1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
@@ -2,7 +2,7 @@ error: using `.clone()` on a ref-counted pointer
   --> tests/ui/unnecessary_clone.rs:23:5
    |
 LL |     rc.clone();
-   |     ^^^^^^^^^^ help: try: `Rc::<bool>::clone(&rc)`
+   |     ^^^^^^^^^^ help: try: `std::rc::Rc::<bool>::clone(&rc)`
    |
    = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::clone_on_ref_ptr)]`
@@ -11,25 +11,25 @@ error: using `.clone()` on a ref-counted pointer
   --> tests/ui/unnecessary_clone.rs:28:5
    |
 LL |     arc.clone();
-   |     ^^^^^^^^^^^ help: try: `Arc::<bool>::clone(&arc)`
+   |     ^^^^^^^^^^^ help: try: `std::sync::Arc::<bool>::clone(&arc)`
 
 error: using `.clone()` on a ref-counted pointer
   --> tests/ui/unnecessary_clone.rs:33:5
    |
 LL |     rcweak.clone();
-   |     ^^^^^^^^^^^^^^ help: try: `Weak::<bool>::clone(&rcweak)`
+   |     ^^^^^^^^^^^^^^ help: try: `std::rc::Weak::<bool>::clone(&rcweak)`
 
 error: using `.clone()` on a ref-counted pointer
   --> tests/ui/unnecessary_clone.rs:38:5
    |
 LL |     arc_weak.clone();
-   |     ^^^^^^^^^^^^^^^^ help: try: `Weak::<bool>::clone(&arc_weak)`
+   |     ^^^^^^^^^^^^^^^^ help: try: `std::sync::Weak::<bool>::clone(&arc_weak)`
 
 error: using `.clone()` on a ref-counted pointer
   --> tests/ui/unnecessary_clone.rs:44:33
    |
 LL |     let _: Arc<dyn SomeTrait> = x.clone();
-   |                                 ^^^^^^^^^ help: try: `Arc::<SomeImpl>::clone(&x)`
+   |                                 ^^^^^^^^^ help: try: `std::sync::Arc::<SomeImpl>::clone(&x)`
 
 error: using `clone` on type `T` which implements the `Copy` trait
   --> tests/ui/unnecessary_clone.rs:49:5
@@ -56,7 +56,7 @@ error: using `.clone()` on a ref-counted pointer
   --> tests/ui/unnecessary_clone.rs:108:14
    |
 LL |         Some(try_opt!(Some(rc)).clone())
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Rc::<u8>::clone(&try_opt!(Some(rc)))`
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::rc::Rc::<u8>::clone(&try_opt!(Some(rc)))`
 
 error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
index 2081772d06b..339d4a95084 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
@@ -9,6 +9,11 @@
 )]
 #![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
 
+struct S {
+    x: u8,
+    y: u8,
+}
+
 fn main() {
     // Should be ignored by this lint, as nesting requires more characters.
     if let &0 | &2 = &0 {}
@@ -45,10 +50,6 @@ fn main() {
     //~^ unnested_or_patterns
     if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {}
     //~^ unnested_or_patterns
-    struct S {
-        x: u8,
-        y: u8,
-    }
     if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
     //~^ unnested_or_patterns
     if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
@@ -77,3 +78,19 @@ mod issue9952 {
     fn or_in_param((x | x | x): i32) {}
     //~^ unnested_or_patterns
 }
+
+fn issue15219() {
+    struct Foo {
+        x: u8,
+    }
+
+    // the original repro
+    if let Foo { x } | Foo { x } = (Foo { x: 0 }) {}
+
+    // also works with more fields
+    if let S { x, y } | S { x, y } = (S { x: 0, y: 0 }) {}
+
+    // `y` not triggering the lint doesn't stop the `x` from getting flagged
+    if let S { y, x: 0 | 1 } = (S { x: 0, y: 1 }) {}
+    //~^ unnested_or_patterns
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
index 6bf8fce3661..f5c99183b0c 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.rs
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
@@ -9,6 +9,11 @@
 )]
 #![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
 
+struct S {
+    x: u8,
+    y: u8,
+}
+
 fn main() {
     // Should be ignored by this lint, as nesting requires more characters.
     if let &0 | &2 = &0 {}
@@ -45,10 +50,6 @@ fn main() {
     //~^ unnested_or_patterns
     if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {}
     //~^ unnested_or_patterns
-    struct S {
-        x: u8,
-        y: u8,
-    }
     if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
     //~^ unnested_or_patterns
     if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
@@ -77,3 +78,19 @@ mod issue9952 {
     fn or_in_param((x | (x | x)): i32) {}
     //~^ unnested_or_patterns
 }
+
+fn issue15219() {
+    struct Foo {
+        x: u8,
+    }
+
+    // the original repro
+    if let Foo { x } | Foo { x } = (Foo { x: 0 }) {}
+
+    // also works with more fields
+    if let S { x, y } | S { x, y } = (S { x: 0, y: 0 }) {}
+
+    // `y` not triggering the lint doesn't stop the `x` from getting flagged
+    if let S { y, x: 0 } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
+    //~^ unnested_or_patterns
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
index c805dc992b1..d2b617c322c 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
@@ -1,5 +1,5 @@
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:16:12
+  --> tests/ui/unnested_or_patterns.rs:21:12
    |
 LL |     if let box 0 | box 2 = Box::new(0) {}
    |            ^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     if let box (0 | 2) = Box::new(0) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:18:12
+  --> tests/ui/unnested_or_patterns.rs:23:12
    |
 LL |     if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL +     if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:21:12
+  --> tests/ui/unnested_or_patterns.rs:26:12
    |
 LL |     if let Some(1) | C0 | Some(2) = None {}
    |            ^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL +     if let Some(1 | 2) | C0 = None {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:23:12
+  --> tests/ui/unnested_or_patterns.rs:28:12
    |
 LL |     if let &mut 0 | &mut 2 = &mut 0 {}
    |            ^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL +     if let &mut (0 | 2) = &mut 0 {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:25:12
+  --> tests/ui/unnested_or_patterns.rs:30:12
    |
 LL |     if let x @ 0 | x @ 2 = 0 {}
    |            ^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL +     if let x @ (0 | 2) = 0 {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:27:12
+  --> tests/ui/unnested_or_patterns.rs:32:12
    |
 LL |     if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL +     if let (0, 1 | 2 | 3) = (0, 0) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:29:12
+  --> tests/ui/unnested_or_patterns.rs:34:12
    |
 LL |     if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL +     if let (1 | 2 | 3, 0) = (0, 0) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:31:12
+  --> tests/ui/unnested_or_patterns.rs:36:12
    |
 LL |     if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL +     if let (x, ..) | (x, 1 | 2) = (0, 1) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:33:12
+  --> tests/ui/unnested_or_patterns.rs:38:12
    |
 LL |     if let [0] | [1] = [0] {}
    |            ^^^^^^^^^
@@ -109,7 +109,7 @@ LL +     if let [0 | 1] = [0] {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:35:12
+  --> tests/ui/unnested_or_patterns.rs:40:12
    |
 LL |     if let [x, 0] | [x, 1] = [0, 1] {}
    |            ^^^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL +     if let [x, 0 | 1] = [0, 1] {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:37:12
+  --> tests/ui/unnested_or_patterns.rs:42:12
    |
 LL |     if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL +     if let [x, 0 | 1 | 2] = [0, 1] {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:39:12
+  --> tests/ui/unnested_or_patterns.rs:44:12
    |
 LL |     if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL +     if let [x, ..] | [x, 1 | 2] = [0, 1] {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:42:12
+  --> tests/ui/unnested_or_patterns.rs:47:12
    |
 LL |     if let TS(0, x) | TS(1, x) = TS(0, 0) {}
    |            ^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL +     if let TS(0 | 1, x) = TS(0, 0) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:44:12
+  --> tests/ui/unnested_or_patterns.rs:49:12
    |
 LL |     if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL +     if let TS(1 | 2 | 3, 0) = TS(0, 0) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:46:12
+  --> tests/ui/unnested_or_patterns.rs:51:12
    |
 LL |     if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL +     if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:52:12
+  --> tests/ui/unnested_or_patterns.rs:53:12
    |
 LL |     if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL +     if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:64:12
+  --> tests/ui/unnested_or_patterns.rs:65:12
    |
 LL |     if let [1] | [53] = [0] {}
    |            ^^^^^^^^^^
@@ -205,7 +205,7 @@ LL +     if let [1 | 53] = [0] {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:70:13
+  --> tests/ui/unnested_or_patterns.rs:71:13
    |
 LL |         let (0 | (1 | _)) = 0;
    |             ^^^^^^^^^^^^^
@@ -217,7 +217,7 @@ LL +         let (0 | 1 | _) = 0;
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:73:16
+  --> tests/ui/unnested_or_patterns.rs:74:16
    |
 LL |         if let (0 | (1 | _)) = 0 {}
    |                ^^^^^^^^^^^^^
@@ -229,7 +229,7 @@ LL +         if let (0 | 1 | _) = 0 {}
    |
 
 error: unnested or-patterns
-  --> tests/ui/unnested_or_patterns.rs:77:20
+  --> tests/ui/unnested_or_patterns.rs:78:20
    |
 LL |     fn or_in_param((x | (x | x)): i32) {}
    |                    ^^^^^^^^^^^^^
@@ -240,5 +240,17 @@ LL -     fn or_in_param((x | (x | x)): i32) {}
 LL +     fn or_in_param((x | x | x): i32) {}
    |
 
-error: aborting due to 20 previous errors
+error: unnested or-patterns
+  --> tests/ui/unnested_or_patterns.rs:94:12
+   |
+LL |     if let S { y, x: 0 } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL -     if let S { y, x: 0 } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
+LL +     if let S { y, x: 0 | 1 } = (S { x: 0, y: 1 }) {}
+   |
+
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
index def8ef86e3c..8e12bd2c8c7 100644
--- a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
@@ -127,14 +127,10 @@ mod issue14577 {
     trait Unit {}
     impl Unit for () {}
 
-    fn run<R: Unit>(f: impl FnOnce() -> R) {
-        f();
-    }
-
     #[allow(dependency_on_unit_never_type_fallback)]
     fn bar() {
-        run(|| { todo!() }); 
         //~[edition2021]^ unused_unit
+        panic!()
     }
 
     struct UnitStruct;
@@ -150,3 +146,24 @@ mod pr14962 {
     type UnusedParensButNoUnit = Box<dyn (Fn())>;
 }
 
+
+mod issue15035 {
+
+    trait Convert<T> {
+        fn from(value: T) -> Self;
+    }
+
+    impl Convert<u64> for () {
+        fn from(_value: u64) -> Self {}
+    }
+
+    fn handle<T: Convert<u64>>(value: u64) -> T {
+        Convert::from(value)
+    }
+
+    pub fn f() -> Option<bool> {
+        let result: Result<bool, u64> = Err(42);
+        // the `-> ()` is required for the inference of `handle`'s return type
+        result.map_err(|err| -> () { handle(err) }).ok()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr
index 13cc20d4d7a..9ad3c2df915 100644
--- a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr
@@ -119,10 +119,10 @@ LL | fn test3()-> (){}
    |           ^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> tests/ui/unused_unit.rs:136:15
+  --> tests/ui/unused_unit.rs:131:13
    |
-LL |         run(|| -> () { todo!() }); 
-   |               ^^^^^^ help: remove the `-> ()`
+LL |     fn bar() -> () {
+   |             ^^^^^^ help: remove the `-> ()`
 
 error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
index f908b958b19..688d2fe9afa 100644
--- a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
@@ -127,14 +127,10 @@ mod issue14577 {
     trait Unit {}
     impl Unit for () {}
 
-    fn run<R: Unit>(f: impl FnOnce() -> R) {
-        f();
-    }
-
     #[allow(dependency_on_unit_never_type_fallback)]
-    fn bar() {
-        run(|| -> () { todo!() }); 
+    fn bar() -> () {
         //~[edition2021]^ unused_unit
+        panic!()
     }
 
     struct UnitStruct;
@@ -150,3 +146,24 @@ mod pr14962 {
     type UnusedParensButNoUnit = Box<dyn (Fn())>;
 }
 
+
+mod issue15035 {
+
+    trait Convert<T> {
+        fn from(value: T) -> Self;
+    }
+
+    impl Convert<u64> for () {
+        fn from(_value: u64) -> Self {}
+    }
+
+    fn handle<T: Convert<u64>>(value: u64) -> T {
+        Convert::from(value)
+    }
+
+    pub fn f() -> Option<bool> {
+        let result: Result<bool, u64> = Err(42);
+        // the `-> ()` is required for the inference of `handle`'s return type
+        result.map_err(|err| -> () { handle(err) }).ok()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs
index 7298ec40cc2..31e980f2655 100644
--- a/src/tools/clippy/tests/ui/unused_unit.rs
+++ b/src/tools/clippy/tests/ui/unused_unit.rs
@@ -127,14 +127,10 @@ mod issue14577 {
     trait Unit {}
     impl Unit for () {}
 
-    fn run<R: Unit>(f: impl FnOnce() -> R) {
-        f();
-    }
-
     #[allow(dependency_on_unit_never_type_fallback)]
-    fn bar() {
-        run(|| -> () { todo!() }); 
+    fn bar() -> () {
         //~[edition2021]^ unused_unit
+        panic!()
     }
 
     struct UnitStruct;
@@ -150,3 +146,24 @@ mod pr14962 {
     type UnusedParensButNoUnit = Box<dyn (Fn())>;
 }
 
+
+mod issue15035 {
+
+    trait Convert<T> {
+        fn from(value: T) -> Self;
+    }
+
+    impl Convert<u64> for () {
+        fn from(_value: u64) -> Self {}
+    }
+
+    fn handle<T: Convert<u64>>(value: u64) -> T {
+        Convert::from(value)
+    }
+
+    pub fn f() -> Option<bool> {
+        let result: Result<bool, u64> = Err(42);
+        // the `-> ()` is required for the inference of `handle`'s return type
+        result.map_err(|err| -> () { handle(err) }).ok()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.rs b/src/tools/clippy/tests/ui/unwrap_in_result.rs
index 4e872c67b42..70c28fe54f3 100644
--- a/src/tools/clippy/tests/ui/unwrap_in_result.rs
+++ b/src/tools/clippy/tests/ui/unwrap_in_result.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::unwrap_in_result)]
+#![allow(clippy::ok_expect)]
 
 struct A;
 
@@ -20,10 +21,9 @@ impl A {
 
     // should be detected
     fn bad_divisible_by_3(i_str: String) -> Result<bool, String> {
-        //~^ unwrap_in_result
-
         // checks whether a string represents a number divisible by 3
         let i = i_str.parse::<i32>().unwrap();
+        //~^ unwrap_in_result
         if i % 3 == 0 {
             Ok(true)
         } else {
@@ -32,9 +32,8 @@ impl A {
     }
 
     fn example_option_expect(i_str: String) -> Option<bool> {
+        let i = i_str.parse::<i32>().ok().expect("not a number");
         //~^ unwrap_in_result
-
-        let i = i_str.parse::<i32>().expect("not a number");
         if i % 3 == 0 {
             return Some(true);
         }
@@ -42,13 +41,66 @@ impl A {
     }
 
     fn in_closure(a: Option<bool>) -> Option<bool> {
-        //~^ unwrap_in_result
+        // No lint inside a closure
         let c = || a.unwrap();
-        Some(c())
+
+        // But lint outside
+        let a = c().then_some(true);
+        let _ = a.unwrap();
+        //~^ unwrap_in_result
+
+        None
     }
+
+    const fn in_const_inside_fn() -> bool {
+        const A: bool = {
+            const fn inner(b: Option<bool>) -> Option<bool> {
+                Some(b.unwrap())
+                //~^ unwrap_in_result
+            }
+
+            // No lint inside `const`
+            inner(Some(true)).unwrap()
+        };
+        A
+    }
+
+    fn in_static_inside_fn() -> bool {
+        static A: bool = {
+            const fn inner(b: Option<bool>) -> Option<bool> {
+                Some(b.unwrap())
+                //~^ unwrap_in_result
+            }
+
+            // No lint inside `static`
+            inner(Some(true)).unwrap()
+        };
+        A
+    }
+}
+
+macro_rules! mac {
+    () => {
+        Option::unwrap(Some(3))
+    };
+}
+
+fn type_relative_unwrap() -> Option<()> {
+    _ = Option::unwrap(Some(3));
+    //~^ unwrap_in_result
+
+    // Do not lint macro output
+    _ = mac!();
+
+    None
 }
 
-fn main() {
-    A::bad_divisible_by_3("3".to_string());
-    A::good_divisible_by_3("3".to_string());
+fn main() -> Result<(), ()> {
+    A::bad_divisible_by_3("3".to_string()).unwrap();
+    //~^ unwrap_in_result
+    A::good_divisible_by_3("3".to_string()).unwrap();
+    //~^ unwrap_in_result
+    Result::unwrap(A::good_divisible_by_3("3".to_string()));
+    //~^ unwrap_in_result
+    Ok(())
 }
diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.stderr b/src/tools/clippy/tests/ui/unwrap_in_result.stderr
index 5e3eab813e0..804b44246dc 100644
--- a/src/tools/clippy/tests/ui/unwrap_in_result.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_in_result.stderr
@@ -1,55 +1,107 @@
-error: used unwrap or expect in a function that returns result or option
-  --> tests/ui/unwrap_in_result.rs:22:5
-   |
-LL | /     fn bad_divisible_by_3(i_str: String) -> Result<bool, String> {
-...  |
-LL | |     }
-   | |_____^
-   |
-   = help: unwrap and expect should not be used in a function that returns result or option
-note: potential non-recoverable error(s)
-  --> tests/ui/unwrap_in_result.rs:26:17
+error: `unwrap` used in a function that returns a `Result`
+  --> tests/ui/unwrap_in_result.rs:25:17
    |
 LL |         let i = i_str.parse::<i32>().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: in this function signature
+  --> tests/ui/unwrap_in_result.rs:23:45
+   |
+LL |     fn bad_divisible_by_3(i_str: String) -> Result<bool, String> {
+   |                                             ^^^^^^^^^^^^^^^^^^^^
+   = help: consider using the `?` operator or calling the `.map_err()` method
    = note: `-D clippy::unwrap-in-result` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_in_result)]`
 
-error: used unwrap or expect in a function that returns result or option
-  --> tests/ui/unwrap_in_result.rs:34:5
+error: `expect` used in a function that returns an `Option`
+  --> tests/ui/unwrap_in_result.rs:35:17
+   |
+LL |         let i = i_str.parse::<i32>().ok().expect("not a number");
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: in this function signature
+  --> tests/ui/unwrap_in_result.rs:34:48
+   |
+LL |     fn example_option_expect(i_str: String) -> Option<bool> {
+   |                                                ^^^^^^^^^^^^
+   = help: consider using the `?` operator
+
+error: `unwrap` used in a function that returns an `Option`
+  --> tests/ui/unwrap_in_result.rs:49:17
+   |
+LL |         let _ = a.unwrap();
+   |                 ^^^^^^^^^^
+   |
+note: in this function signature
+  --> tests/ui/unwrap_in_result.rs:43:39
+   |
+LL |     fn in_closure(a: Option<bool>) -> Option<bool> {
+   |                                       ^^^^^^^^^^^^
+   = help: consider using the `?` operator
+
+error: `unwrap` used in a function that returns an `Option`
+  --> tests/ui/unwrap_in_result.rs:58:22
    |
-LL | /     fn example_option_expect(i_str: String) -> Option<bool> {
-LL | |
-LL | |
-LL | |         let i = i_str.parse::<i32>().expect("not a number");
-...  |
-LL | |         None
-LL | |     }
-   | |_____^
+LL |                 Some(b.unwrap())
+   |                      ^^^^^^^^^^
    |
-   = help: unwrap and expect should not be used in a function that returns result or option
-note: potential non-recoverable error(s)
-  --> tests/ui/unwrap_in_result.rs:37:17
+note: in this function signature
+  --> tests/ui/unwrap_in_result.rs:57:48
    |
-LL |         let i = i_str.parse::<i32>().expect("not a number");
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             const fn inner(b: Option<bool>) -> Option<bool> {
+   |                                                ^^^^^^^^^^^^
+   = help: consider using the `?` operator
 
-error: used unwrap or expect in a function that returns result or option
-  --> tests/ui/unwrap_in_result.rs:44:5
+error: `unwrap` used in a function that returns an `Option`
+  --> tests/ui/unwrap_in_result.rs:71:22
    |
-LL | /     fn in_closure(a: Option<bool>) -> Option<bool> {
-LL | |
-LL | |         let c = || a.unwrap();
-LL | |         Some(c())
-LL | |     }
-   | |_____^
+LL |                 Some(b.unwrap())
+   |                      ^^^^^^^^^^
    |
-   = help: unwrap and expect should not be used in a function that returns result or option
-note: potential non-recoverable error(s)
-  --> tests/ui/unwrap_in_result.rs:46:20
+note: in this function signature
+  --> tests/ui/unwrap_in_result.rs:70:48
+   |
+LL |             const fn inner(b: Option<bool>) -> Option<bool> {
+   |                                                ^^^^^^^^^^^^
+   = help: consider using the `?` operator
+
+error: `unwrap` used in a function that returns an `Option`
+  --> tests/ui/unwrap_in_result.rs:89:9
+   |
+LL |     _ = Option::unwrap(Some(3));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: in this function signature
+  --> tests/ui/unwrap_in_result.rs:88:30
+   |
+LL | fn type_relative_unwrap() -> Option<()> {
+   |                              ^^^^^^^^^^
+   = help: consider using the `?` operator
+
+error: `unwrap` used in a function that returns a `Result`
+  --> tests/ui/unwrap_in_result.rs:99:5
+   |
+LL |     A::bad_divisible_by_3("3".to_string()).unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: in this function signature
+  --> tests/ui/unwrap_in_result.rs:98:14
+   |
+LL | fn main() -> Result<(), ()> {
+   |              ^^^^^^^^^^^^^^
+   = help: consider using the `?` operator or calling the `.map_err()` method
+
+error: `unwrap` used in a function that returns a `Result`
+  --> tests/ui/unwrap_in_result.rs:101:5
+   |
+LL |     A::good_divisible_by_3("3".to_string()).unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `unwrap` used in a function that returns a `Result`
+  --> tests/ui/unwrap_in_result.rs:103:5
    |
-LL |         let c = || a.unwrap();
-   |                    ^^^^^^^^^^
+LL |     Result::unwrap(A::good_divisible_by_3("3".to_string()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed
index f360a8afadf..55742459c92 100644
--- a/src/tools/clippy/tests/ui/vec.fixed
+++ b/src/tools/clippy/tests/ui/vec.fixed
@@ -242,3 +242,12 @@ fn issue_12101() {
     for a in &[1, 2] {}
     //~^ useless_vec
 }
+
+fn issue_14531() {
+    // The lint used to suggest using an array rather than a reference to a slice.
+
+    fn requires_ref_slice(v: &[()]) {}
+    let v = &[];
+    //~^ useless_vec
+    requires_ref_slice(v);
+}
diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs
index a779d33557c..fbf7131323c 100644
--- a/src/tools/clippy/tests/ui/vec.rs
+++ b/src/tools/clippy/tests/ui/vec.rs
@@ -242,3 +242,12 @@ fn issue_12101() {
     for a in &(vec![1, 2]) {}
     //~^ useless_vec
 }
+
+fn issue_14531() {
+    // The lint used to suggest using an array rather than a reference to a slice.
+
+    fn requires_ref_slice(v: &[()]) {}
+    let v = &vec![];
+    //~^ useless_vec
+    requires_ref_slice(v);
+}
diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr
index 806d6617200..d16c8a8944a 100644
--- a/src/tools/clippy/tests/ui/vec.stderr
+++ b/src/tools/clippy/tests/ui/vec.stderr
@@ -127,5 +127,11 @@ error: useless use of `vec!`
 LL |     for a in &(vec![1, 2]) {}
    |              ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
-error: aborting due to 21 previous errors
+error: useless use of `vec!`
+  --> tests/ui/vec.rs:250:13
+   |
+LL |     let v = &vec![];
+   |             ^^^^^^^ help: you can use a slice directly: `&[]`
+
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 805baf2af6d..7b19f8658c0 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -49,11 +49,18 @@ new_pr = true
 # These labels are set when there are unresolved concerns, removed otherwise
 labels = ["S-waiting-on-concerns"]
 
+# Show differences when a PR is rebased
+[range-diff]
+
+# Amend a review to include a link to what was changed since the review
+[review-changes-since]
+
 [assign]
 contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
 users_on_vacation = [
     "matthiaskrgr",
     "Manishearth",
+    "flip1995",
 ]
 
 [assign.owners]
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 89b1b4f84b6..143ccdcb9e5 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -67,6 +67,7 @@ string_enum! {
         MirOpt => "mir-opt",
         Pretty => "pretty",
         RunMake => "run-make",
+        RunMakeCargo => "run-make-cargo",
         Rustdoc => "rustdoc",
         RustdocGui => "rustdoc-gui",
         RustdocJs => "rustdoc-js",
@@ -269,9 +270,6 @@ pub struct Config {
     /// between e.g. beta `cargo` vs in-tree `cargo`.
     ///
     /// FIXME: maybe rename this to reflect that this is a *staged* host cargo.
-    ///
-    /// FIXME(#134109): split `run-make` into two test suites, a test suite *with* staged cargo, and
-    /// another test suite *without*.
     pub cargo_path: Option<Utf8PathBuf>,
 
     /// Path to the stage 0 `rustc` used to build `run-make` recipes. This must not be confused with
@@ -667,6 +665,10 @@ pub struct Config {
     /// to avoid `!nocapture` double-negatives.
     pub nocapture: bool,
 
+    /// True if the experimental new output-capture implementation should be
+    /// used, avoiding the need for `#![feature(internal_output_capture)]`.
+    pub new_output_capture: bool,
+
     /// Needed both to construct [`build_helper::git::GitConfig`].
     pub nightly_branch: String,
     pub git_merge_commit_email: String,
@@ -784,6 +786,7 @@ impl Config {
             builtin_cfg_names: Default::default(),
             supported_crate_types: Default::default(),
             nocapture: Default::default(),
+            new_output_capture: Default::default(),
             nightly_branch: Default::default(),
             git_merge_commit_email: Default::default(),
             profiler_runtime: Default::default(),
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index f2ad049d526..857953072c4 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -1012,7 +1012,7 @@ impl Config {
         if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number)
         {
             if self.mode == TestMode::RunMake {
-                panic!("`run-make` tests do not support revisions: {}", testfile);
+                panic!("`run-make` mode tests do not support revisions: {}", testfile);
             }
 
             let mut duplicates: HashSet<_> = existing.iter().cloned().collect();
diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs
index 5519ef1af1f..b0dc24798b6 100644
--- a/src/tools/compiletest/src/executor.rs
+++ b/src/tools/compiletest/src/executor.rs
@@ -13,6 +13,7 @@ use std::sync::{Arc, Mutex, mpsc};
 use std::{env, hint, io, mem, panic, thread};
 
 use crate::common::{Config, TestPaths};
+use crate::output_capture::{self, ConsoleOut};
 use crate::panic_hook;
 
 mod deadline;
@@ -120,28 +121,28 @@ fn run_test_inner(
     runnable_test: RunnableTest,
     completion_sender: mpsc::Sender<TestCompletion>,
 ) {
-    let is_capture = !runnable_test.config.nocapture;
+    let capture = CaptureKind::for_config(&runnable_test.config);
 
     // Install a panic-capture buffer for use by the custom panic hook.
-    if is_capture {
+    if capture.should_set_panic_hook() {
         panic_hook::set_capture_buf(Default::default());
     }
-    let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![])));
 
-    if let Some(capture_buf) = &capture_buf {
-        io::set_output_capture(Some(Arc::clone(capture_buf)));
+    if let CaptureKind::Old { ref buf } = capture {
+        io::set_output_capture(Some(Arc::clone(buf)));
     }
 
-    let panic_payload = panic::catch_unwind(move || runnable_test.run()).err();
+    let stdout = capture.stdout();
+    let stderr = capture.stderr();
+
+    let panic_payload = panic::catch_unwind(move || runnable_test.run(stdout, stderr)).err();
 
     if let Some(panic_buf) = panic_hook::take_capture_buf() {
         let panic_buf = panic_buf.lock().unwrap_or_else(|e| e.into_inner());
-        // For now, forward any captured panic message to (captured) stderr.
-        // FIXME(Zalathar): Once we have our own output-capture buffer for
-        // non-panic output, append the panic message to that buffer instead.
-        eprint!("{panic_buf}");
+        // Forward any captured panic message to (captured) stderr.
+        write!(stderr, "{panic_buf}");
     }
-    if is_capture {
+    if matches!(capture, CaptureKind::Old { .. }) {
         io::set_output_capture(None);
     }
 
@@ -152,11 +153,70 @@ fn run_test_inner(
             TestOutcome::Failed { message: Some("test did not panic as expected") }
         }
     };
-    let stdout = capture_buf.map(|mutex| mutex.lock().unwrap_or_else(|e| e.into_inner()).to_vec());
 
+    let stdout = capture.into_inner();
     completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap();
 }
 
+enum CaptureKind {
+    /// Do not capture test-runner output, for `--no-capture`.
+    ///
+    /// (This does not affect `rustc` and other subprocesses spawned by test
+    /// runners, whose output is always captured.)
+    None,
+
+    /// Use the old output-capture implementation, which relies on the unstable
+    /// library feature `#![feature(internal_output_capture)]`.
+    Old { buf: Arc<Mutex<Vec<u8>>> },
+
+    /// Use the new output-capture implementation, which only uses stable Rust.
+    New { buf: output_capture::CaptureBuf },
+}
+
+impl CaptureKind {
+    fn for_config(config: &Config) -> Self {
+        if config.nocapture {
+            Self::None
+        } else if config.new_output_capture {
+            Self::New { buf: output_capture::CaptureBuf::new() }
+        } else {
+            // Create a capure buffer for `io::set_output_capture`.
+            Self::Old { buf: Default::default() }
+        }
+    }
+
+    fn should_set_panic_hook(&self) -> bool {
+        match self {
+            Self::None => false,
+            Self::Old { .. } => true,
+            Self::New { .. } => true,
+        }
+    }
+
+    fn stdout(&self) -> &dyn ConsoleOut {
+        self.capture_buf_or(&output_capture::Stdout)
+    }
+
+    fn stderr(&self) -> &dyn ConsoleOut {
+        self.capture_buf_or(&output_capture::Stderr)
+    }
+
+    fn capture_buf_or<'a>(&'a self, fallback: &'a dyn ConsoleOut) -> &'a dyn ConsoleOut {
+        match self {
+            Self::None | Self::Old { .. } => fallback,
+            Self::New { buf } => buf,
+        }
+    }
+
+    fn into_inner(self) -> Option<Vec<u8>> {
+        match self {
+            Self::None => None,
+            Self::Old { buf } => Some(buf.lock().unwrap_or_else(|e| e.into_inner()).to_vec()),
+            Self::New { buf } => Some(buf.into_inner().into()),
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 struct TestId(usize);
 
@@ -174,10 +234,12 @@ impl RunnableTest {
         Self { config, testpaths, revision }
     }
 
-    fn run(&self) {
+    fn run(&self, stdout: &dyn ConsoleOut, stderr: &dyn ConsoleOut) {
         __rust_begin_short_backtrace(|| {
             crate::runtest::run(
                 Arc::clone(&self.config),
+                stdout,
+                stderr,
                 &self.testpaths,
                 self.revision.as_deref(),
             );
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index fa84691a46f..f647f96a9bf 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -15,6 +15,7 @@ pub mod directives;
 pub mod errors;
 mod executor;
 mod json;
+mod output_capture;
 mod panic_hook;
 mod raise_fd_limit;
 mod read2;
@@ -177,6 +178,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
         // FIXME: Temporarily retained so we can point users to `--no-capture`
         .optflag("", "nocapture", "")
         .optflag("", "no-capture", "don't capture stdout/stderr of tests")
+        .optopt(
+            "N",
+            "new-output-capture",
+            "enables or disables the new output-capture implementation",
+            "off|on",
+        )
         .optflag("", "profiler-runtime", "is the profiler runtime enabled for this target")
         .optflag("h", "help", "show this message")
         .reqopt("", "channel", "current Rust channel", "CHANNEL")
@@ -461,6 +468,14 @@ pub fn parse_config(args: Vec<String>) -> Config {
         supported_crate_types: OnceLock::new(),
 
         nocapture: matches.opt_present("no-capture"),
+        new_output_capture: {
+            let value = matches
+                .opt_str("new-output-capture")
+                .or_else(|| env::var("COMPILETEST_NEW_OUTPUT_CAPTURE").ok())
+                .unwrap_or_else(|| "off".to_owned());
+            parse_bool_option(&value)
+                .unwrap_or_else(|| panic!("unknown `--new-output-capture` value `{value}` given"))
+        },
 
         nightly_branch: matches.opt_str("nightly-branch").unwrap(),
         git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
@@ -476,6 +491,19 @@ pub fn parse_config(args: Vec<String>) -> Config {
     }
 }
 
+/// Parses the same set of boolean values accepted by rustc command-line arguments.
+///
+/// Accepting all of these values is more complicated than just picking one
+/// pair, but has the advantage that contributors who are used to rustc
+/// shouldn't have to think about which values are legal.
+fn parse_bool_option(value: &str) -> Option<bool> {
+    match value {
+        "off" | "no" | "n" | "false" => Some(false),
+        "on" | "yes" | "y" | "true" => Some(true),
+        _ => None,
+    }
+}
+
 pub fn opt_str(maybestr: &Option<String>) -> &str {
     match *maybestr {
         None => "(none)",
diff --git a/src/tools/compiletest/src/output_capture.rs b/src/tools/compiletest/src/output_capture.rs
new file mode 100644
index 00000000000..de1aea11ade
--- /dev/null
+++ b/src/tools/compiletest/src/output_capture.rs
@@ -0,0 +1,52 @@
+use std::fmt;
+use std::panic::RefUnwindSafe;
+use std::sync::Mutex;
+
+pub trait ConsoleOut: fmt::Debug + RefUnwindSafe {
+    fn write_fmt(&self, args: fmt::Arguments<'_>);
+}
+
+#[derive(Debug)]
+pub(crate) struct Stdout;
+
+impl ConsoleOut for Stdout {
+    fn write_fmt(&self, args: fmt::Arguments<'_>) {
+        print!("{args}");
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct Stderr;
+
+impl ConsoleOut for Stderr {
+    fn write_fmt(&self, args: fmt::Arguments<'_>) {
+        eprint!("{args}");
+    }
+}
+
+pub(crate) struct CaptureBuf {
+    inner: Mutex<String>,
+}
+
+impl CaptureBuf {
+    pub(crate) fn new() -> Self {
+        Self { inner: Mutex::new(String::new()) }
+    }
+
+    pub(crate) fn into_inner(self) -> String {
+        self.inner.into_inner().unwrap_or_else(|e| e.into_inner())
+    }
+}
+
+impl fmt::Debug for CaptureBuf {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("CaptureBuf").finish_non_exhaustive()
+    }
+}
+
+impl ConsoleOut for CaptureBuf {
+    fn write_fmt(&self, args: fmt::Arguments<'_>) {
+        let mut s = self.inner.lock().unwrap_or_else(|e| e.into_inner());
+        <String as fmt::Write>::write_fmt(&mut s, args).unwrap();
+    }
+}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 867624cc8fa..89fb8eb4357 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -23,6 +23,7 @@ use crate::common::{
 };
 use crate::directives::TestProps;
 use crate::errors::{Error, ErrorKind, load_errors};
+use crate::output_capture::ConsoleOut;
 use crate::read2::{Truncated, read2_abbreviated};
 use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
 use crate::util::{Utf8PathBufExt, add_dylib_path, static_regex};
@@ -108,7 +109,13 @@ fn dylib_name(name: &str) -> String {
     format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
 }
 
-pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
+pub fn run(
+    config: Arc<Config>,
+    stdout: &dyn ConsoleOut,
+    stderr: &dyn ConsoleOut,
+    testpaths: &TestPaths,
+    revision: Option<&str>,
+) {
     match &*config.target {
         "arm-linux-androideabi"
         | "armv7-linux-androideabi"
@@ -131,7 +138,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
 
     if config.verbose {
         // We're going to be dumping a lot of info. Start on a new line.
-        print!("\n\n");
+        write!(stdout, "\n\n");
     }
     debug!("running {}", testpaths.file);
     let mut props = TestProps::from_file(&testpaths.file, revision, &config);
@@ -143,7 +150,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
         props.incremental_dir = Some(incremental_dir(&config, testpaths, revision));
     }
 
-    let cx = TestCx { config: &config, props: &props, testpaths, revision };
+    let cx = TestCx { config: &config, stdout, stderr, props: &props, testpaths, revision };
 
     if let Err(e) = create_dir_all(&cx.output_base_dir()) {
         panic!("failed to create output base directory {}: {e}", cx.output_base_dir());
@@ -162,6 +169,8 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
             revision_props.incremental_dir = props.incremental_dir.clone();
             let rev_cx = TestCx {
                 config: &config,
+                stdout,
+                stderr,
                 props: &revision_props,
                 testpaths,
                 revision: Some(revision),
@@ -212,6 +221,8 @@ pub fn compute_stamp_hash(config: &Config) -> String {
 #[derive(Copy, Clone, Debug)]
 struct TestCx<'test> {
     config: &'test Config,
+    stdout: &'test dyn ConsoleOut,
+    stderr: &'test dyn ConsoleOut,
     props: &'test TestProps,
     testpaths: &'test TestPaths,
     revision: Option<&'test str>,
@@ -603,7 +614,8 @@ impl<'test> TestCx<'test> {
             );
         } else {
             for pattern in missing_patterns {
-                println!(
+                writeln!(
+                    self.stdout,
                     "\n{prefix}: error pattern '{pattern}' not found!",
                     prefix = self.error_prefix()
                 );
@@ -783,7 +795,8 @@ impl<'test> TestCx<'test> {
                 };
                 format!("{file_name}:{line_num}{opt_col_num}")
             };
-            let print_error = |e| println!("{}: {}: {}", line_str(e), e.kind, e.msg.cyan());
+            let print_error =
+                |e| writeln!(self.stdout, "{}: {}: {}", line_str(e), e.kind, e.msg.cyan());
             let push_suggestion =
                 |suggestions: &mut Vec<_>, e: &Error, kind, line, msg, color, rank| {
                     let mut ret = String::new();
@@ -811,7 +824,7 @@ impl<'test> TestCx<'test> {
                 if let Some(&(_, top_rank)) = suggestions.first() {
                     for (suggestion, rank) in suggestions {
                         if rank == top_rank {
-                            println!("  {} {suggestion}", prefix.color(color));
+                            writeln!(self.stdout, "  {} {suggestion}", prefix.color(color));
                         }
                     }
                 }
@@ -824,7 +837,8 @@ impl<'test> TestCx<'test> {
             // - only known line - meh, but suggested
             // - others are not worth suggesting
             if !unexpected.is_empty() {
-                println!(
+                writeln!(
+                    self.stdout,
                     "\n{prefix}: {n} diagnostics reported in JSON output but not expected in test file",
                     prefix = self.error_prefix(),
                     n = unexpected.len(),
@@ -858,7 +872,8 @@ impl<'test> TestCx<'test> {
                 }
             }
             if !not_found.is_empty() {
-                println!(
+                writeln!(
+                    self.stdout,
                     "\n{prefix}: {n} diagnostics expected in test file but not reported in JSON output",
                     prefix = self.error_prefix(),
                     n = not_found.len(),
@@ -978,6 +993,8 @@ impl<'test> TestCx<'test> {
                     self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
                 let aux_cx = TestCx {
                     config: self.config,
+                    stdout: self.stdout,
+                    stderr: self.stderr,
                     props: &props_for_aux,
                     testpaths: &aux_testpaths,
                     revision: self.revision,
@@ -1343,6 +1360,8 @@ impl<'test> TestCx<'test> {
         let aux_output = TargetLocation::ThisDirectory(aux_dir.clone());
         let aux_cx = TestCx {
             config: self.config,
+            stdout: self.stdout,
+            stderr: self.stderr,
             props: &aux_props,
             testpaths: &aux_testpaths,
             revision: self.revision,
@@ -1948,11 +1967,11 @@ impl<'test> TestCx<'test> {
         } else {
             path.file_name().unwrap().into()
         };
-        println!("------{proc_name} stdout------------------------------");
-        println!("{}", out);
-        println!("------{proc_name} stderr------------------------------");
-        println!("{}", err);
-        println!("------------------------------------------");
+        writeln!(self.stdout, "------{proc_name} stdout------------------------------");
+        writeln!(self.stdout, "{}", out);
+        writeln!(self.stdout, "------{proc_name} stderr------------------------------");
+        writeln!(self.stdout, "{}", err);
+        writeln!(self.stdout, "------------------------------------------");
     }
 
     fn dump_output_file(&self, out: &str, extension: &str) {
@@ -2014,7 +2033,7 @@ impl<'test> TestCx<'test> {
         debug!("{message}");
         if self.config.verbose {
             // Note: `./x test ... --verbose --no-capture` is needed to see this print.
-            println!("{message}");
+            writeln!(self.stdout, "{message}");
         }
     }
 
@@ -2030,7 +2049,7 @@ impl<'test> TestCx<'test> {
 
     #[track_caller]
     fn fatal(&self, err: &str) -> ! {
-        println!("\n{prefix}: {err}", prefix = self.error_prefix());
+        writeln!(self.stdout, "\n{prefix}: {err}", prefix = self.error_prefix());
         error!("fatal error, panic: {:?}", err);
         panic!("fatal error");
     }
@@ -2048,15 +2067,15 @@ impl<'test> TestCx<'test> {
         proc_res: &ProcRes,
         callback_before_unwind: impl FnOnce(),
     ) -> ! {
-        println!("\n{prefix}: {err}", prefix = self.error_prefix());
+        writeln!(self.stdout, "\n{prefix}: {err}", prefix = self.error_prefix());
 
         // Some callers want to print additional notes after the main error message.
         if let Some(note) = extra_note {
-            println!("{note}");
+            writeln!(self.stdout, "{note}");
         }
 
         // Print the details and output of the subprocess that caused this test to fail.
-        println!("{}", proc_res.format_info());
+        writeln!(self.stdout, "{}", proc_res.format_info());
 
         // Some callers want print more context or show a custom diff before the unwind occurs.
         callback_before_unwind();
@@ -2126,7 +2145,7 @@ impl<'test> TestCx<'test> {
         if !self.config.has_html_tidy {
             return;
         }
-        println!("info: generating a diff against nightly rustdoc");
+        writeln!(self.stdout, "info: generating a diff against nightly rustdoc");
 
         let suffix =
             self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly");
@@ -2162,7 +2181,7 @@ impl<'test> TestCx<'test> {
 
         let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths);
         if !proc_res.status.success() {
-            eprintln!("failed to run nightly rustdoc");
+            writeln!(self.stderr, "failed to run nightly rustdoc");
             return;
         }
 
@@ -2207,6 +2226,7 @@ impl<'test> TestCx<'test> {
         let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id());
 
         if !write_filtered_diff(
+            self,
             &diff_filename,
             out_dir,
             &compare_dir,
@@ -2227,7 +2247,7 @@ impl<'test> TestCx<'test> {
         if let Some(pager) = pager {
             let pager = pager.trim();
             if self.config.verbose {
-                eprintln!("using pager {}", pager);
+                writeln!(self.stderr, "using pager {}", pager);
             }
             let output = Command::new(pager)
                 // disable paging; we want this to be non-interactive
@@ -2238,8 +2258,8 @@ impl<'test> TestCx<'test> {
                 .output()
                 .unwrap();
             assert!(output.status.success());
-            println!("{}", String::from_utf8_lossy(&output.stdout));
-            eprintln!("{}", String::from_utf8_lossy(&output.stderr));
+            writeln!(self.stdout, "{}", String::from_utf8_lossy(&output.stdout));
+            writeln!(self.stderr, "{}", String::from_utf8_lossy(&output.stderr));
         } else {
             warning!("no pager configured, falling back to unified diff");
             help!(
@@ -2254,7 +2274,7 @@ impl<'test> TestCx<'test> {
                 match diff.read_until(b'\n', &mut line) {
                     Ok(0) => break,
                     Ok(_) => {}
-                    Err(e) => eprintln!("ERROR: {:?}", e),
+                    Err(e) => writeln!(self.stderr, "ERROR: {:?}", e),
                 }
                 match String::from_utf8(line.clone()) {
                     Ok(line) => {
@@ -2802,11 +2822,11 @@ impl<'test> TestCx<'test> {
         if let Err(err) = fs::write(&actual_path, &actual) {
             self.fatal(&format!("failed to write {stream} to `{actual_path}`: {err}",));
         }
-        println!("Saved the actual {stream} to `{actual_path}`");
+        writeln!(self.stdout, "Saved the actual {stream} to `{actual_path}`");
 
         if !self.config.bless {
             if expected.is_empty() {
-                println!("normalized {}:\n{}\n", stream, actual);
+                writeln!(self.stdout, "normalized {}:\n{}\n", stream, actual);
             } else {
                 self.show_diff(
                     stream,
@@ -2830,14 +2850,15 @@ impl<'test> TestCx<'test> {
                 if let Err(err) = fs::write(&expected_path, &actual) {
                     self.fatal(&format!("failed to write {stream} to `{expected_path}`: {err}"));
                 }
-                println!(
+                writeln!(
+                    self.stdout,
                     "Blessing the {stream} of `{test_name}` as `{expected_path}`",
                     test_name = self.testpaths.file
                 );
             }
         }
 
-        println!("\nThe actual {stream} differed from the expected {stream}");
+        writeln!(self.stdout, "\nThe actual {stream} differed from the expected {stream}");
 
         if self.config.bless { CompareOutcome::Blessed } else { CompareOutcome::Differed }
     }
@@ -2852,7 +2873,7 @@ impl<'test> TestCx<'test> {
         actual: &str,
         actual_unnormalized: &str,
     ) {
-        eprintln!("diff of {stream}:\n");
+        writeln!(self.stderr, "diff of {stream}:\n");
         if let Some(diff_command) = self.config.diff_command.as_deref() {
             let mut args = diff_command.split_whitespace();
             let name = args.next().unwrap();
@@ -2864,11 +2885,11 @@ impl<'test> TestCx<'test> {
                 }
                 Ok(output) => {
                     let output = String::from_utf8_lossy(&output.stdout);
-                    eprint!("{output}");
+                    write!(self.stderr, "{output}");
                 }
             }
         } else {
-            eprint!("{}", write_diff(expected, actual, 3));
+            write!(self.stderr, "{}", write_diff(expected, actual, 3));
         }
 
         // NOTE: argument order is important, we need `actual` to be on the left so the line number match up when we compare it to `actual_unnormalized` below.
@@ -2906,9 +2927,16 @@ impl<'test> TestCx<'test> {
             && !mismatches_unnormalized.is_empty()
             && !mismatches_normalized.is_empty()
         {
-            eprintln!("Note: some mismatched output was normalized before being compared");
+            writeln!(
+                self.stderr,
+                "Note: some mismatched output was normalized before being compared"
+            );
             // FIXME: respect diff_command
-            eprint!("{}", write_diff(&mismatches_unnormalized, &mismatches_normalized, 0));
+            write!(
+                self.stderr,
+                "{}",
+                write_diff(&mismatches_unnormalized, &mismatches_normalized, 0)
+            );
         }
     }
 
@@ -2986,7 +3014,7 @@ impl<'test> TestCx<'test> {
         fs::create_dir_all(&incremental_dir).unwrap();
 
         if self.config.verbose {
-            println!("init_incremental_test: incremental_dir={incremental_dir}");
+            writeln!(self.stdout, "init_incremental_test: incremental_dir={incremental_dir}");
         }
     }
 }
diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs
index 44ddcb1d288..16c251c3c9e 100644
--- a/src/tools/compiletest/src/runtest/codegen_units.rs
+++ b/src/tools/compiletest/src/runtest/codegen_units.rs
@@ -62,13 +62,13 @@ impl TestCx<'_> {
         if !missing.is_empty() {
             missing.sort();
 
-            println!("\nThese items should have been contained but were not:\n");
+            writeln!(self.stdout, "\nThese items should have been contained but were not:\n");
 
             for item in &missing {
-                println!("{}", item);
+                writeln!(self.stdout, "{}", item);
             }
 
-            println!("\n");
+            writeln!(self.stdout, "\n");
         }
 
         if !unexpected.is_empty() {
@@ -78,24 +78,32 @@ impl TestCx<'_> {
                 sorted
             };
 
-            println!("\nThese items were contained but should not have been:\n");
+            writeln!(self.stdout, "\nThese items were contained but should not have been:\n");
 
             for item in sorted {
-                println!("{}", item);
+                writeln!(self.stdout, "{}", item);
             }
 
-            println!("\n");
+            writeln!(self.stdout, "\n");
         }
 
         if !wrong_cgus.is_empty() {
             wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
-            println!("\nThe following items were assigned to wrong codegen units:\n");
+            writeln!(self.stdout, "\nThe following items were assigned to wrong codegen units:\n");
 
             for &(ref expected_item, ref actual_item) in &wrong_cgus {
-                println!("{}", expected_item.name);
-                println!("  expected: {}", codegen_units_to_str(&expected_item.codegen_units));
-                println!("  actual:   {}", codegen_units_to_str(&actual_item.codegen_units));
-                println!();
+                writeln!(self.stdout, "{}", expected_item.name);
+                writeln!(
+                    self.stdout,
+                    "  expected: {}",
+                    codegen_units_to_str(&expected_item.codegen_units)
+                );
+                writeln!(
+                    self.stdout,
+                    "  actual:   {}",
+                    codegen_units_to_str(&actual_item.codegen_units)
+                );
+                writeln!(self.stdout);
             }
         }
 
diff --git a/src/tools/compiletest/src/runtest/compute_diff.rs b/src/tools/compiletest/src/runtest/compute_diff.rs
index 509e7e11703..3363127b3ea 100644
--- a/src/tools/compiletest/src/runtest/compute_diff.rs
+++ b/src/tools/compiletest/src/runtest/compute_diff.rs
@@ -3,6 +3,8 @@ use std::fs::{File, FileType};
 
 use camino::Utf8Path;
 
+use crate::runtest::TestCx;
+
 #[derive(Debug, PartialEq)]
 pub enum DiffLine {
     Context(String),
@@ -112,6 +114,7 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S
 ///
 /// Returns whether any data was actually written.
 pub(crate) fn write_filtered_diff<Filter>(
+    cx: &TestCx<'_>,
     diff_filename: &str,
     out_dir: &Utf8Path,
     compare_dir: &Utf8Path,
@@ -147,11 +150,11 @@ where
     }
 
     if !wrote_data {
-        println!("note: diff is identical to nightly rustdoc");
+        writeln!(cx.stdout, "note: diff is identical to nightly rustdoc");
         assert!(diff_output.metadata().unwrap().len() == 0);
         return false;
     } else if verbose {
-        eprintln!("printing diff:");
+        writeln!(cx.stderr, "printing diff:");
         let mut buf = Vec::new();
         diff_output.read_to_end(&mut buf).unwrap();
         std::io::stderr().lock().write_all(&mut buf).unwrap();
diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs
index da1e74b4a56..0aae7eaa39c 100644
--- a/src/tools/compiletest/src/runtest/crashes.rs
+++ b/src/tools/compiletest/src/runtest/crashes.rs
@@ -6,10 +6,10 @@ impl TestCx<'_> {
         let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm));
 
         if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() {
-            eprintln!("{}", proc_res.status);
-            eprintln!("{}", proc_res.stdout);
-            eprintln!("{}", proc_res.stderr);
-            eprintln!("{}", proc_res.cmdline);
+            writeln!(self.stderr, "{}", proc_res.status);
+            writeln!(self.stderr, "{}", proc_res.stdout);
+            writeln!(self.stderr, "{}", proc_res.stderr);
+            writeln!(self.stderr, "{}", proc_res.cmdline);
         }
 
         // if a test does not crash, consider it an error
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 88d022b8bba..071c0863b7e 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -245,7 +245,7 @@ impl TestCx<'_> {
                 cmdline,
             };
             if adb.kill().is_err() {
-                println!("Adb process is already finished.");
+                writeln!(self.stdout, "Adb process is already finished.");
             }
         } else {
             let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc");
@@ -256,7 +256,11 @@ impl TestCx<'_> {
 
             match self.config.gdb_version {
                 Some(version) => {
-                    println!("NOTE: compiletest thinks it is using GDB version {}", version);
+                    writeln!(
+                        self.stdout,
+                        "NOTE: compiletest thinks it is using GDB version {}",
+                        version
+                    );
 
                     if !self.props.disable_gdb_pretty_printers
                         && version > extract_gdb_version("7.4").unwrap()
@@ -278,7 +282,8 @@ impl TestCx<'_> {
                     }
                 }
                 _ => {
-                    println!(
+                    writeln!(
+                        self.stdout,
                         "NOTE: compiletest does not know which version of \
                          GDB it is using"
                     );
@@ -376,10 +381,15 @@ impl TestCx<'_> {
 
         match self.config.lldb_version {
             Some(ref version) => {
-                println!("NOTE: compiletest thinks it is using LLDB version {}", version);
+                writeln!(
+                    self.stdout,
+                    "NOTE: compiletest thinks it is using LLDB version {}",
+                    version
+                );
             }
             _ => {
-                println!(
+                writeln!(
+                    self.stdout,
                     "NOTE: compiletest does not know which version of \
                      LLDB it is using"
                 );
diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs
index 90cff6bab4d..44eb80300c3 100644
--- a/src/tools/compiletest/src/runtest/incremental.rs
+++ b/src/tools/compiletest/src/runtest/incremental.rs
@@ -30,7 +30,7 @@ impl TestCx<'_> {
         assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
 
         if self.config.verbose {
-            print!("revision={:?} props={:#?}", revision, self.props);
+            write!(self.stdout, "revision={:?} props={:#?}", revision, self.props);
         }
 
         if revision.starts_with("cpass") {
diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs
index 55043bf4bc2..94487926383 100644
--- a/src/tools/compiletest/src/runtest/mir_opt.rs
+++ b/src/tools/compiletest/src/runtest/mir_opt.rs
@@ -80,7 +80,7 @@ impl TestCx<'_> {
                 }
                 let expected_string = fs::read_to_string(&expected_file).unwrap();
                 if dumped_string != expected_string {
-                    print!("{}", write_diff(&expected_string, &dumped_string, 3));
+                    write!(self.stdout, "{}", write_diff(&expected_string, &dumped_string, 3));
                     panic!(
                         "Actual MIR output differs from expected MIR output {}",
                         expected_file.display()
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index 8a0e45cf8ca..738f504d5c1 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -5,11 +5,12 @@ use build_helper::fs::{ignore_not_found, recursive_remove};
 use camino::{Utf8Path, Utf8PathBuf};
 
 use super::{ProcRes, TestCx, disable_error_reporting};
+use crate::common::TestSuite;
 use crate::util::{copy_dir_all, dylib_env_var};
 
 impl TestCx<'_> {
     pub(super) fn run_rmake_test(&self) {
-        // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe
+        // For `run-make`, we need to perform 2 steps to build and run a `run-make` recipe
         // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust
         // library and is available under
         // `build/$HOST/bootstrap-tools/$TARGET/release/librun_make_support.rlib`.
@@ -189,8 +190,12 @@ impl TestCx<'_> {
             // through a specific CI runner).
             .env("LLVM_COMPONENTS", &self.config.llvm_components);
 
-        if let Some(ref cargo) = self.config.cargo_path {
-            cmd.env("CARGO", cargo);
+        // Only `run-make-cargo` test suite gets an in-tree `cargo`, not `run-make`.
+        if self.config.suite == TestSuite::RunMakeCargo {
+            cmd.env(
+                "CARGO",
+                self.config.cargo_path.as_ref().expect("cargo must be built and made available"),
+            );
         }
 
         if let Some(ref rustdoc) = self.config.rustdoc_path {
diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs
index 083398f9274..b8da6e2ac52 100644
--- a/src/tools/compiletest/src/runtest/rustdoc_json.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs
@@ -30,8 +30,8 @@ impl TestCx<'_> {
 
         if !res.status.success() {
             self.fatal_proc_rec_general("jsondocck failed!", None, &res, || {
-                println!("Rustdoc Output:");
-                println!("{}", proc_res.format_info());
+                writeln!(self.stdout, "Rustdoc Output:");
+                writeln!(self.stdout, "{}", proc_res.format_info());
             })
         }
 
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index 40b0ee0a399..d683a325c86 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -115,10 +115,14 @@ impl TestCx<'_> {
         }
 
         if errors > 0 {
-            println!("To update references, rerun the tests and pass the `--bless` flag");
+            writeln!(
+                self.stdout,
+                "To update references, rerun the tests and pass the `--bless` flag"
+            );
             let relative_path_to_file =
                 self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap());
-            println!(
+            writeln!(
+                self.stdout,
                 "To only update this specific test, also pass `--test-args {}`",
                 relative_path_to_file,
             );
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 1f16a672a98..558e9a58697 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -45,7 +45,7 @@ impl Utf8PathBufExt for Utf8PathBuf {
 
 /// The name of the environment variable that holds dynamic library locations.
 pub fn dylib_env_var() -> &'static str {
-    if cfg!(windows) {
+    if cfg!(any(windows, target_os = "cygwin")) {
         "PATH"
     } else if cfg!(target_vendor = "apple") {
         "DYLD_LIBRARY_PATH"
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 7d79c384f85..c0fed96d4e6 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -41,6 +41,11 @@ jobs:
             multiarch: s390x
             gcc_cross: s390x-linux-gnu
             qemu: true
+          - host_target: powerpc64le-unknown-linux-gnu
+            os: ubuntu-latest
+            multiarch: ppc64el
+            gcc_cross: powerpc64le-linux-gnu
+            qemu: true
           - host_target: aarch64-apple-darwin
             os: macos-latest
           - host_target: i686-pc-windows-msvc
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 7d78fdddbad..073ad267476 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -255,6 +255,12 @@ when installing the Miri toolchain. Alternatively, set the `RUSTUP_TOOLCHAIN` en
 
 [`etc/rust_analyzer_helix.toml`]: https://github.com/rust-lang/miri/blob/master/etc/rust_analyzer_helix.toml
 
+### Zed
+
+Copy [`etc/rust_analyzer_zed.json`] to `.zed/settings.json` in the project root directory.
+
+[`etc/rust_analyzer_zed.json`]: https://github.com/rust-lang/miri/blob/master/etc/rust_analyzer_zed.json
+
 ### Advanced configuration
 
 If you are building Miri with a locally built rustc, set
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index b46f0f83420..4df17c83c7e 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -1569,9 +1569,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.19"
+version = "0.3.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
+checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
 dependencies = [
  "sharded-slab",
  "thread_local",
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 99111092d39..924dfed2bca 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -39,7 +39,7 @@ features = ['unprefixed_malloc_on_supported_platforms']
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
 # native-lib dependencies
-libffi = { version = "4.0.0", optional = true }
+libffi = { version = "4.1.1", optional = true }
 libloading = { version = "0.8", optional = true }
 serde = { version = "1.0.219", features = ["derive"], optional = true }
 
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 7ccd27d7b83..517aa343a6d 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -319,8 +319,14 @@ environment variable. We first document the most relevant and most commonly used
   Can be used without a value; in that case the range defaults to `0..64`.
 * `-Zmiri-many-seeds-keep-going` tells Miri to really try all the seeds in the given range, even if
   a failing seed has already been found. This is useful to determine which fraction of seeds fails.
+* `-Zmiri-max-extra-rounding-error` tells Miri to always apply the maximum error to float operations
+  that do not have a guaranteed precision. The sign of the error is still non-deterministic.
 * `-Zmiri-no-extra-rounding-error` stops Miri from adding extra rounding errors to float operations
   that do not have a guaranteed precision.
+* `-Zmiri-no-short-fd-operations` stops Miri from artificially forcing `read`/`write` operations
+  to only process a part of their buffer. Note that whenever Miri uses host operations to
+  implement `read`/`write` (e.g. for file-backed file descriptors), the host system can still
+  introduce short reads/writes.
 * `-Zmiri-num-cpus` states the number of available CPUs to be reported by miri. By default, the
   number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
   any way.
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index b3f5dafab64..ea9c04a3cb5 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -429,9 +429,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.9"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdb13874a0e55baf4ac3d49d38206aecb31a55b75d6c4d04fd850b53942c8cc8"
+checksum = "dd41ead66a69880951b2f7df3139db401d44451b4da123344d27eaa791b89c95"
 dependencies = [
  "anyhow",
  "rustc_version",
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 77cb1df8e74..64b56ea114e 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -18,7 +18,7 @@ directories = "6"
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.21"
-rustc-build-sysroot = "0.5.8"
+rustc-build-sysroot = "0.5.10"
 
 # 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/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index efb9053f69a..0716f4add9d 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -65,16 +65,6 @@ fn forward_patched_extern_arg(args: &mut impl Iterator<Item = String>, cmd: &mut
 }
 
 pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
-    // Check for version and help flags even when invoked as `cargo-miri`.
-    if has_arg_flag("--help") || has_arg_flag("-h") {
-        show_help();
-        return;
-    }
-    if has_arg_flag("--version") || has_arg_flag("-V") {
-        show_version();
-        return;
-    }
-
     // Require a subcommand before any flags.
     // We cannot know which of those flags take arguments and which do not,
     // so we cannot detect subcommands later.
@@ -85,11 +75,36 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
         "setup" => MiriCommand::Setup,
         "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
         "clean" => MiriCommand::Clean,
-        _ =>
+        _ => {
+            // Check for version and help flags.
+            if has_arg_flag("--help") || has_arg_flag("-h") {
+                show_help();
+                return;
+            }
+            if has_arg_flag("--version") || has_arg_flag("-V") {
+                show_version();
+                return;
+            }
             show_error!(
                 "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`."
-            ),
+            )
+        }
     };
+    if has_arg_flag("--help") || has_arg_flag("-h") {
+        match subcommand {
+            MiriCommand::Forward(verb) => {
+                println!("`cargo miri {verb}` supports the same flags as `cargo {verb}`:\n");
+                let mut cmd = cargo();
+                cmd.arg(verb);
+                cmd.arg("--help");
+                exec(cmd);
+            }
+            _ => {
+                show_help();
+                return;
+            }
+        }
+    }
     let verbose = num_arg_flag("-v") + num_arg_flag("--verbose");
     let quiet = has_arg_flag("-q") || has_arg_flag("--quiet");
 
diff --git a/src/tools/miri/doc/img/perfetto_aggregate_statistics.png b/src/tools/miri/doc/img/perfetto_aggregate_statistics.png
new file mode 100644
index 00000000000..d4fd3826f47
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_aggregate_statistics.png
Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_aggregate_statistics_sql.png b/src/tools/miri/doc/img/perfetto_aggregate_statistics_sql.png
new file mode 100644
index 00000000000..bda92d3885a
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_aggregate_statistics_sql.png
Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_span.png b/src/tools/miri/doc/img/perfetto_span.png
new file mode 100644
index 00000000000..1a7184f22ae
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_span.png
Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_subname_statistics.png b/src/tools/miri/doc/img/perfetto_subname_statistics.png
new file mode 100644
index 00000000000..8c86b07e925
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_subname_statistics.png
Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_timeline.png b/src/tools/miri/doc/img/perfetto_timeline.png
new file mode 100644
index 00000000000..49f8a1fac1d
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_timeline.png
Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_visualize_argument_values.png b/src/tools/miri/doc/img/perfetto_visualize_argument_values.png
new file mode 100644
index 00000000000..1dcbacaf9cb
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_visualize_argument_values.png
Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_visualize_argument_values_misbehaving.png b/src/tools/miri/doc/img/perfetto_visualize_argument_values_misbehaving.png
new file mode 100644
index 00000000000..beeba8a4a3a
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_visualize_argument_values_misbehaving.png
Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_visualize_argument_values_sql.png b/src/tools/miri/doc/img/perfetto_visualize_argument_values_sql.png
new file mode 100644
index 00000000000..c7b163b0a57
--- /dev/null
+++ b/src/tools/miri/doc/img/perfetto_visualize_argument_values_sql.png
Binary files differdiff --git a/src/tools/miri/doc/tracing.md b/src/tools/miri/doc/tracing.md
new file mode 100644
index 00000000000..d7114af947d
--- /dev/null
+++ b/src/tools/miri/doc/tracing.md
@@ -0,0 +1,292 @@
+# Documentation for the tracing infrastructure in Miri
+
+Miri can be traced to understand how much time is spent in its various components (e.g. borrow tracker, data race checker, etc.). When tracing is enabled, running Miri will create a `.json` trace file that can be opened and analyzed in [Perfetto](https://ui.perfetto.dev/). For any questions regarding this documentation you may contact [Stypox](https://rust-lang.zulipchat.com/#narrow/dm/627563-Stypox) on Zulip.
+
+## Obtaining a trace file
+
+### From the Miri codebase
+
+All of the tracing functionality in Miri is gated by the `"tracing"` feature flag to ensure it does not create any overhead when unneeded. To compile Miri with this feature enabled, you can pass `--features=tracing` to `./miri`. Then, to make running Miri actually produce a trace file, you also need to set the `MIRI_TRACING` environment variable. For example:
+
+```sh
+MIRI_TRACING=1 ./miri run --features=tracing ./tests/pass/hello.rs
+```
+
+### From the rustc codebase
+
+If you are building Miri from within the rustc tree, you need to enable the `"tracing"` feature by adding this line to `bootstrap.toml`:
+
+```toml
+build.tool.miri.features = ["tracing"]
+```
+
+And then you could run the following:
+
+```sh
+MIRI_TRACING=1 ./x.py run miri --stage 1 --args ./src/tools/miri/tests/pass/hello.rs
+```
+
+### The trace file
+
+After running Miri with tracing enabled you will get a `.json` trace file that contains a list of all events and spans that occurred throughout the execution. The file follows [this format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview).
+
+## Analyzing a trace file
+
+To analyze traces you can use [Perfetto UI](https://ui.perfetto.dev/), a trace analyzer made by Google that was originally a part of the Chrome browser. Just open Perfetto and drag and drop the `.json` file there. Official documentation for the controls in the UI can be found [here](https://perfetto.dev/docs/visualization/perfetto-ui).
+
+### The timeline
+
+You will see the boxes "Global Legacy Events" and "Process 1" on the left of the workspace: after clicking on either of them their timeline will expand and you will be able to zoom in and look at individual spans (and events).
+
+- "Process 1" contains tracing spans for the various components of Miri, all in a single timeline line (e.g. borrow tracker, data race checker, etc.)
+- "Global Legacy Events" contains auxiliary spans on two separate lines that allow understanding what code is being executed at any point in time:
+    - "frame": what is the current stack frame in the interpreted program
+    - "step": what statement/terminator in the MIR of the interpreted program is being executed
+
+Spans are represented as colored boxes in the timeline, while instantaneous events are represented by tiny arrows. (Events exist because rustc and Miri also use the `tracing` crate for debug logging, and those logs turn into events in the trace.)
+
+![](./img/perfetto_timeline.png)
+
+### Span/event data
+
+You can click on a span or an event to get more information about it, including some arguments that were passed when the span/event was entered/fired. In the following screenshot you can see the details of a "layouting" span that was generated by the following line in Miri's code:
+
+```rust
+let _trace = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args);
+```
+
+![](./img/perfetto_span.png)
+
+### SQL tables
+
+Perfetto supports querying the span/event database using SQL queries (see the [docs](https://perfetto.dev/docs/analysis/perfetto-sql-syntax)). Just type `:` in the search bar at the top to enter SQL mode, and then you will be able to enter SQL queries there. The relevant SQL tables are:
+- `slices`: contains all spans and events; events can be distinguished from spans since their `dur` is 0. Relevant columns are:
+    - `id`: a unique primary-key ID for the span (assigned by Perfetto, not present in the trace file)
+    - `ts` and `dur`: the beginning and duration of the span, in nanoseconds
+    - `name`: the name of the span
+    - `parent_id`: the parent span ID, or null if there is no parent (assigned by Perfetto based on the timing at which spans occur, i.e. two nested spans must be one the child of the other)
+    - `arg_set_id`: a foreign key into the table of arguments (1-to-N)
+- `args`: contains all of the arguments of the various events/spans. Relevant columns are:
+    - `arg_set_id`: the key used to join the slices and args tables
+    - `key`: the name of the argument prepended with "args."
+    - `display_value`: the value of the argument
+
+Some useful queries are provided in the following sections.
+
+### Enhancing the timeline
+
+On the "Process 1" timeline line there are some spans with the same name, that are actually generated from different places in Miri's code. In those cases the span name indicates the component that was invoked (e.g. the data race checker), but not the specific function that was run. To inspect the specific function, we store a "subname" in an argument with the same name as the span, which unfortunately can be seen only after clicking on the span.
+
+To make it quicker to look at subnames, you can add a new timeline line that specifically shows the subnames for spans with a specific name. To do so:
+1. select any span with the name you care about (call this name `$NAME`)
+2. click on the dropdown highlighted in blue next on the argument with name `$NAME` (or `args.$NAME`)
+3. click on "Visualize argument values"
+4. a new timeline line will appear with only spans originally named `$NAME`, but now with the subname displayed instead
+
+The following screenshot shows the 4 steps for spans named "data_race":
+
+![](./img/perfetto_visualize_argument_values.png)
+
+### Visualizing which "frame" or "step" is being executed
+
+Unfortunately the instructions in [Enhancing the timeline](#enhancing-the-timeline) only work well with spans under "Process 1", but misbehave with spans under "Global Legacy Events" (see the screenshot below). This might be a bug in Perfetto, but nevertheless a workaround is available:
+
+1. click on the search bar at the top and write `:` to enter SQL mode
+2. copy-paste the following SQL, replace "SPAN_NAME" at the end with either "frame" or "step" (i.e. one of the two span names under "Global Legacy Events"), and press Enter to execute it:
+    ```sql
+    select slices.id, ts, dur, track_id, category, args.string_value as name, depth, stack_id, parent_stack_id, parent_id, slices.arg_set_id, thread_ts, thread_instruction_count, thread_instruction_delta, cat, slice_id
+    from slices inner join args using (arg_set_id)
+    where args.key = "args." || name and name = "SPAN_NAME"
+    ```
+3. at the top-right of the box at the bottom, click on "Show debug track"
+4. press on "Show" in the popup that just appeared
+5. a new debug track will appear with the names of steps or frames
+
+What the SQL does is to select only spans with the name "SPAN_NAME" and keep all of the span fields untouched, except for the name which is replaced with the subname. As explained in [Enhancing the timeline](#enhancing-the-timeline), remember that the subname is stored in an argument with the same name as the span.
+
+![](./img/perfetto_visualize_argument_values_sql.png)
+
+<img src="./img/perfetto_visualize_argument_values_misbehaving.png" width="300px">
+
+### Compute aggregate statistics
+
+The simplest way to get aggregate statistics about a time range is to:
+
+1. select a time range by drag-clicking along a trace line
+2. click on the "Current Selection" tab at the bottom if it's not already open
+3. see various tables/visualizations of how much time is spent in each span by clicking on "Slices", "Pivot Table" or "Slice Flamegraph"
+
+Note that the numbers shown in the "Slices" and "Pivot Table" tabs also include nested spans, so they cannot be used to compute statistics such as "X% of time is spent in spans named Y" because two spans named Y might be nested and their duration would be counted twice. For such statistics use the method in [Compute aggregate statistics (enhanced)](#compute-aggregate-statistics-enhanced).
+
+![](./img/perfetto_aggregate_statistics.png)
+
+### Compute aggregate statistics (enhanced)
+
+The following (long but not complicated) query can be used to find out how much time is spent in spans (grouped by their name). Only spans without a parent are considered towards the computations (see `where parent_id is null`): so for example if `validate_operand` in turn calls `layouting` (which generates a nested/child span), only the `validate_operand` statistics are increased. This query also excludes auxiliary spans (see `name != "frame" and name != "step"`).
+
+Note that this query does not allow selecting a time range, but that can be done by adding a condition, e.g. `ts + dur > MIN_T and ts < MAX_T` would match only spans that intersect the range `(MIN_T, MAX_T)`. Remember that the time unit is nanoseconds.
+
+```sql
+select "TOTAL PROGRAM DURATION" as name, count(*), max(ts + dur) as "sum(dur)", 100.0 as "%", null as "min(dur)", null as "max(dur)", null as "avg(dur)", null as "stddev(dur)"
+from slices
+
+union select "TOTAL OVER ALL SPANS (excluding events)" as name, count(*), sum(dur), cast(cast(sum(dur) as float) / (select max(ts + dur) from slices) * 1000 as int) / 10.0 as "%", min(dur), max(dur), cast(avg(dur) as int) as "avg(dur)", cast(sqrt(avg(dur*dur)-avg(dur)*avg(dur)) as int) as "stddev(dur)"
+from slices
+where parent_id is null and name != "frame" and name != "step" and dur > 0
+
+union select name, count(*), sum(dur), cast(cast(sum(dur) as float) / (select max(ts + dur) from slices) * 1000 as int) / 10.0 as "%", min(dur), max(dur), cast(avg(dur) as int) as "avg(dur)", cast(sqrt(avg(dur*dur)-avg(dur)*avg(dur)) as int) as "stddev(dur)"
+from slices
+where parent_id is null and name != "frame" and name != "step"
+group by name
+order by sum(dur) desc, count(*) desc
+```
+
+This is the kind of table you would get out:
+
+![](./img/perfetto_aggregate_statistics_sql.png)
+
+### Statistics about subnames of a span
+
+Use the following SQL to see statistics about the subnames of spans with the same name (replace "SPAN_NAME" with the name of the span you want to see subname statistics of):
+
+```sql
+select args.string_value as name, count(*), sum(dur), min(dur), max(dur), cast(avg(dur) as int) as "avg(dur)", cast(sqrt(avg(dur*dur)-avg(dur)*avg(dur)) as int) as "stddev(dur)"
+from slices inner join args using (arg_set_id)
+where args.key = "args." || name and name = "SPAN_NAME"
+group by args.string_value
+order by count(*) desc
+```
+
+For example, this is the table of how much time is spent in each borrow tracker function: 
+
+![](./img/perfetto_subname_statistics.png)
+
+### Finding long periods of time without any tracing
+
+The following SQL finds the longest periods of time where time is being spent, with the ability to click on IDs in the table of results to quickly reach the corresponding place. This can be useful to spot things that use up a significant amount of time but that are not yet covered by tracing calls.
+
+```sql
+with ordered as (
+    select s1.*, row_number() over (order by s1.ts) as rn
+    from slices as s1
+    where s1.parent_id is null and s1.dur > 0 and s1.name != "frame" and s1.name != "step"
+)
+select a.ts+a.dur as ts, b.ts-a.ts-a.dur as dur, a.id, a.track_id, a.category, a.depth, a.stack_id, a.parent_stack_id, a.parent_id, a.arg_set_id, a.thread_ts, a.thread_instruction_count, a.thread_instruction_delta, a.cat, a.slice_id, "empty" as name
+from ordered as a inner join ordered as b on a.rn=b.rn-1
+order by b.ts-a.ts-a.dur desc
+```
+
+### Saving Perfetto's state as a preset
+
+Unfortunately Perfetto does not seem to support saving the UI state as a preset that can be used to repeat the same analysis on multiple traces. You have to click through the various menus or run the various SQL queries every time to setup the UI as you want.
+
+## Adding new tracing calls to the code
+
+### The "tracing" feature
+
+Miri is highly interconnected with `rustc_const_eval`, and therefore collecting proper trace data about Miri also involves adding some tracing calls within `rustc_const_eval`'s codebase. As explained in [Obtaining a trace file](#obtaining-a-trace-file), tracing calls are disabled (and optimized out) when Miri's "tracing" feature is not enabled. However, while it is possible to check for the feature from Miri's codebase, it's not possible to do so from `rustc_const_eval` (since it's a separate crate, and it's even in a precompiled `.rlib` in case of out-of-tree builds).
+
+The solution to make it possible to check whether tracing is enabled at compile time even in `rustc_const_eval` was to add a function with this signature to the `Machine` trait:
+```rust
+fn enter_trace_span(span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan
+```
+
+where `EnteredTraceSpan` is just a marker trait implemented by `()` and `tracing::span::EnteredSpan`. This function returns `()` by default (without calling the `span` closure), except in `MiriMachine` where if tracing is enabled it will return `span().entered()`.
+
+The code in `rustc_const_eval` calls this function when it wants to do tracing, and the compiler will (hopefully) optimize out tracing calls when tracing is disabled.
+
+### The `enter_trace_span!()` macro
+
+To add tracing to a section of code in Miri or in `rustc_const_eval`, you can use the `enter_trace_span!()` macro, which takes care of the details explained in [The "tracing" feature](#the-tracing-feature).
+
+The `enter_trace_span!()` macro accepts the same syntax as `tracing::span!()` ([documentation](https://docs.rs/tracing/latest/tracing/#using-the-macros)) except for a few customizations, and returns an already entered trace span. The returned value is a drop guard that will exit the span when dropped, so **make sure to give it a proper scope** by storing it in a variable like this:
+
+```rust
+let _trace = enter_trace_span!("My span");
+```
+
+When calling this macro from `rustc_const_eval` you need to pass a type implementing the `Machine` trait as the first argument (since it will be used to call `Machine::enter_trace_span()`). This is usually available in various parts of `rustc_const_eval` under the name `M`, since most of `rustc_const_eval`'s code is `Machine`-agnostic.
+
+```rust
+let _trace = enter_trace_span!("My span");    // from Miri
+let _trace = enter_trace_span!(M, "My span"); // from rustc_const_eval
+```
+
+You can make sense of the syntaxes explained below also by looking at this Perfetto screenshot from [Span/event data](#spanevent-data).
+
+![](./img/perfetto_span.png)
+
+### Syntax accepted by `tracing::span!()`
+
+The full documentation for the `tracing::span!()` syntax can be found [here](https://docs.rs/tracing/latest/tracing/#using-the-macros) under "Using the Macros". A few possibly confusing syntaxes are listed here:
+```rust
+// logs a span named "hello" with a field named "arg" of value 42 (works only because
+// 42 implements the tracing::Value trait, otherwise use one of the options below)
+let _trace = enter_trace_span!(M, "hello", arg = 42);
+// logs a field called "my_display_var" using the Display implementation
+let _trace = enter_trace_span!(M, "hello", %my_display_var);
+// logs a field called "my_debug_var" using the Debug implementation
+let _trace = enter_trace_span!(M, "hello", ?my_debug_var);
+```
+
+### `NAME::SUBNAME` syntax
+
+In addition to the syntax accepted by `tracing::span!()`, the `enter_trace_span!()` macro optionally allows passing the span name (i.e. the first macro argument) in the form `NAME::SUBNAME` (without quotes) to indicate that the span has name "NAME" (usually the name of the component) and has an additional more specific name "SUBNAME" (usually the function name). The latter is passed to the tracing crate as a span field with the name "NAME". This allows not being distracted by subnames when looking at the trace in Perfetto, but when deeper introspection is needed within a component, it's still possible to view the subnames directly with a few steps (see [Enhancing the timeline](#enhancing-the-timeline)).
+```rust
+// for example, the first will expand to the second
+let _trace = enter_trace_span!(M, borrow_tracker::on_stack_pop);
+let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop");
+```
+
+### `tracing_separate_thread` parameter
+
+Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example:
+```rust
+let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty);
+```
+
+### Executing something else when tracing is disabled
+
+The `EnteredTraceSpan` trait contains a `or_if_tracing_disabled()` function that you can use to e.g. log a line as an alternative to the tracing span for when tracing is disabled. For example:
+```rust
+let _trace = enter_trace_span!(M, step::eval_statement)
+    .or_if_tracing_disabled(|| tracing::info!("eval_statement"));
+```
+
+## Implementation details
+
+Here we explain how tracing is implemented internally.
+
+The events and spans generated throughout the codebase are collected by [the `tracing` crate](https://crates.io/crates/tracing), which then dispatches them to the code that writes to the trace file, but also to the logger if logging is enabled. 
+
+### Choice of tracing library
+
+The crate that was chosen for collecting traces is [tracing](https://crates.io/crates/tracing), since:
+- it is very well maintained
+- it supports various different trace formats through plug-and-play `Layer`s (in Miri we are using `tracing_chrome` to export traces for perfetto, see [The `tracing_chrome` layer](#the-tracing_chrome-layer))
+- spans and events are collected with not just their name, but also file, line, module, and any number of custom arguments
+- it was already used in Miri and rustc as a logging framework 
+
+One major drawback of the tracing crate is, however, its big overhead. Entering and exiting a span takes on the order of 100ns, and many of Miri's spans are shorter than that, so their measurements are completely off and the program execution increases significantly. E.g. at the point of writing this documentation, enabling tracing makes Miri 5x slower. Note that this used to be even worse, see [Time measurements](#time-measurements).
+
+### The `tracing_chrome` layer
+
+Miri uses [tracing-chrome](https://github.com/thoren-d/tracing-chrome) as the `Layer` that collects spans and events from the tracing crate and saves them to a file that can be opened in Perfetto. Although the crate [is published](https://crates.io/crates/tracing-chrome) on crates.io, it was not possible to depend on it from Miri, because it would bring in a separate compilation of the `tracing` crate. This is because Miri does not directly depend on `tracing`, and instead uses rustc's version through rustc-private, and apparently cargo can't realize that the same library is being built again when rustc-private is involved.
+
+So the solution was to copy-paste [the only file](https://github.com/thoren-d/tracing-chrome/blob/develop/src/lib.rs) in tracing-chrome into Miri. Nevertheless, this gave the possibility to make some changes to tracing-chrome, which you can read about in documentation at the top of [the file](https://github.com/rust-lang/miri/blob/master/src/bin/log/tracing_chrome.rs) that was copied to Miri.
+
+### Time measurements
+
+tracing-chrome originally used `std::time::Instant` to measure time, however on some x86/x86_64 Linux systems it might be unbearably slow since the underlying system call (`clock_gettime`) would take ≈1.3µs. Read more [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) about how the Linux kernel chooses the clock source.
+
+Therefore, on x86/x86_64 Linux systems with a CPU that has an invariant TSC counter, we read from that instead to measure time, which takes only ≈13ns. There are unfortunately a lot of caveats to this approach though, as explained [in the code](https://github.com/rust-lang/miri/blob/master/src/bin/log/tracing_chrome_instant.rs) and [in the PR](https://github.com/rust-lang/miri/pull/4524). The most impactful one is that: every thread spawned in Miri that wants to trace something (which requires measuring time) needs to pin itself to a single CPU core (using `sched_setaffinity`).
+
+## Other useful stuff
+
+### Making a flamegraph
+
+After compiling Miri, you can run the following command to make a flamegraph using Linux' `perf`. It can be useful to spot functions that use up a significant amount of time but that are not yet covered by tracing calls.
+
+```sh
+perf record  --call-graph dwarf -F 999 ./miri/target/debug/miri --edition 2021 --sysroot ~/.cache/miri ./tests/pass/hashmap.rs && perf script | inferno-collapse-perf | inferno-flamegraph > flamegraph.svg
+```
diff --git a/src/tools/miri/etc/rust_analyzer_zed.json b/src/tools/miri/etc/rust_analyzer_zed.json
new file mode 100644
index 00000000000..839914c8b68
--- /dev/null
+++ b/src/tools/miri/etc/rust_analyzer_zed.json
@@ -0,0 +1,41 @@
+{
+    "lsp": {
+        "rust-analyzer": {
+            "initialization_options": {
+                "rustc": {
+                    "source": "discover"
+                },
+                "linkedProjects": [
+                    "./Cargo.toml",
+                    "./cargo-miri/Cargo.toml",
+                    "./genmc-sys/Cargo.toml",
+                    "./miri-script/Cargo.toml"
+                ],
+                "check": {
+                    "invocationStrategy": "once",
+                    "overrideCommand": [
+                        "./miri",
+                        "clippy", // make this `check` when working with a locally built rustc
+                        "--message-format=json"
+                    ]
+                },
+                "cargo": {
+                    "extraEnv": {
+                        "MIRI_AUTO_OPS": "no",
+                        "MIRI_IN_RA": "1"
+                    },
+                    // Contrary to what the name suggests, this also affects proc macros.
+                    "buildScripts": {
+                        "invocationStrategy": "once",
+                        "overrideCommand": [
+                            "./miri",
+                            "check",
+                            "--no-default-features",
+                            "--message-format=json"
+                        ]
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 59adc572eaa..d44488399f8 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-f605b57042ffeb320d7ae44490113a827139b766
+51ff895062ba60a7cba53f57af928c3fb7b0f2f4
diff --git a/src/tools/miri/src/bin/log/mod.rs b/src/tools/miri/src/bin/log/mod.rs
index f3b2fdb5348..22f74dd46b5 100644
--- a/src/tools/miri/src/bin/log/mod.rs
+++ b/src/tools/miri/src/bin/log/mod.rs
@@ -1,2 +1,3 @@
 pub mod setup;
 mod tracing_chrome;
+mod tracing_chrome_instant;
diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs
index 3379816550c..310887a13a5 100644
--- a/src/tools/miri/src/bin/log/tracing_chrome.rs
+++ b/src/tools/miri/src/bin/log/tracing_chrome.rs
@@ -7,12 +7,15 @@
 //! (`git log -- path/to/tracing_chrome.rs`), but in summary:
 //! - the file attributes were changed and `extern crate` was added at the top
 //! - if a tracing span has a field called "tracing_separate_thread", it will be given a separate
-//! span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing
-//! the trace in <https://ui.perfetto.dev>. This is the syntax to trigger this behavior:
+//!   span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing
+//!   the trace in <https://ui.perfetto.dev>. This is the syntax to trigger this behavior:
 //!   ```rust
 //!   tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */)
 //!   ```
-//! - use i64 instead of u64 for the "id" in [ChromeLayer::get_root_id] to be compatible with Perfetto
+//! - use i64 instead of u64 for the "id" in [ChromeLayer::get_root_id] to be compatible with
+//!   Perfetto
+//! - use [ChromeLayer::with_elapsed_micros_subtracting_tracing] to make time measurements faster on
+//!   Linux x86/x86_64 and to subtract time spent tracing from the timestamps in the trace file
 //!
 //! Depending on the tracing-chrome crate from crates.io is unfortunately not possible, since it
 //! depends on `tracing_core` which conflicts with rustc_private's `tracing_core` (meaning it would
@@ -50,9 +53,22 @@ use std::{
     thread::JoinHandle,
 };
 
+use crate::log::tracing_chrome_instant::TracingChromeInstant;
+
+/// Contains thread-local data for threads that send tracing spans or events.
+struct ThreadData {
+    /// A unique ID for this thread, will populate "tid" field in the output trace file.
+    tid: usize,
+    /// A clone of [ChromeLayer::out] to avoid the expensive operation of accessing a mutex
+    /// every time. This is used to send [Message]s to the thread that saves trace data to file.
+    out: Sender<Message>,
+    /// The instant in time this thread was started. All events happening on this thread will be
+    /// saved to the trace file with a timestamp (the "ts" field) measured relative to this instant.
+    start: TracingChromeInstant,
+}
+
 thread_local! {
-    static OUT: RefCell<Option<Sender<Message>>> = const { RefCell::new(None) };
-    static TID: RefCell<Option<usize>> = const { RefCell::new(None) };
+    static THREAD_DATA: RefCell<Option<ThreadData>> = const { RefCell::new(None) };
 }
 
 type NameFn<S> = Box<dyn Fn(&EventOrSpan<'_, '_, S>) -> String + Send + Sync>;
@@ -64,7 +80,6 @@ where
     S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
 {
     out: Arc<Mutex<Sender<Message>>>,
-    start: std::time::Instant,
     max_tid: AtomicUsize,
     include_args: bool,
     include_locations: bool,
@@ -323,7 +338,6 @@ where
 {
     fn new(mut builder: ChromeLayerBuilder<S>) -> (ChromeLayer<S>, FlushGuard) {
         let (tx, rx) = mpsc::channel();
-        OUT.with(|val| val.replace(Some(tx.clone())));
 
         let out_writer = builder
             .out_writer
@@ -443,7 +457,6 @@ where
         };
         let layer = ChromeLayer {
             out: Arc::new(Mutex::new(tx)),
-            start: std::time::Instant::now(),
             max_tid: AtomicUsize::new(0),
             name_fn: builder.name_fn.take(),
             cat_fn: builder.cat_fn.take(),
@@ -456,22 +469,7 @@ where
         (layer, guard)
     }
 
-    fn get_tid(&self) -> (usize, bool) {
-        TID.with(|value| {
-            let tid = *value.borrow();
-            match tid {
-                Some(tid) => (tid, false),
-                None => {
-                    let tid = self.max_tid.fetch_add(1, Ordering::SeqCst);
-                    value.replace(Some(tid));
-                    (tid, true)
-                }
-            }
-        })
-    }
-
-    fn get_callsite(&self, data: EventOrSpan<S>) -> Callsite {
-        let (tid, new_thread) = self.get_tid();
+    fn get_callsite(&self, data: EventOrSpan<S>, tid: usize) -> Callsite {
         let name = self.name_fn.as_ref().map(|name_fn| name_fn(&data));
         let target = self.cat_fn.as_ref().map(|cat_fn| cat_fn(&data));
         let meta = match data {
@@ -502,14 +500,6 @@ where
             (None, None)
         };
 
-        if new_thread {
-            let name = match std::thread::current().name() {
-                Some(name) => name.to_owned(),
-                None => tid.to_string(),
-            };
-            self.send_message(Message::NewThread(tid, name));
-        }
-
         Callsite {
             tid,
             name,
@@ -548,31 +538,55 @@ where
         }
     }
 
-    fn enter_span(&self, span: SpanRef<S>, ts: f64) {
-        let callsite = self.get_callsite(EventOrSpan::Span(&span));
+    fn enter_span(&self, span: SpanRef<S>, ts: f64, tid: usize, out: &Sender<Message>) {
+        let callsite = self.get_callsite(EventOrSpan::Span(&span), tid);
         let root_id = self.get_root_id(span);
-        self.send_message(Message::Enter(ts, callsite, root_id));
+        let _ignored = out.send(Message::Enter(ts, callsite, root_id));
     }
 
-    fn exit_span(&self, span: SpanRef<S>, ts: f64) {
-        let callsite = self.get_callsite(EventOrSpan::Span(&span));
+    fn exit_span(&self, span: SpanRef<S>, ts: f64, tid: usize, out: &Sender<Message>) {
+        let callsite = self.get_callsite(EventOrSpan::Span(&span), tid);
         let root_id = self.get_root_id(span);
-        self.send_message(Message::Exit(ts, callsite, root_id));
+        let _ignored = out.send(Message::Exit(ts, callsite, root_id));
     }
 
-    fn get_ts(&self) -> f64 {
-        self.start.elapsed().as_nanos() as f64 / 1000.0
-    }
+    /// Helper function that measures how much time is spent while executing `f` and accounts for it
+    /// in subsequent calls, with the aim to reduce biases in the data collected by `tracing_chrome`
+    /// by subtracting the time spent inside tracing functions from the timeline. This makes it so
+    /// that the time spent inside the `tracing_chrome` functions does not impact the timestamps
+    /// inside the trace file (i.e. `ts`), even if such functions are slow (e.g. because they need
+    /// to format arguments on the same thread those arguments are collected on, otherwise memory
+    /// safety would be broken).
+    ///
+    /// `f` is called with the microseconds elapsed since the current thread was started (**not**
+    /// since the program start!), with the current thread ID (i.e. `tid`), and with a [Sender] that
+    /// can be used to send a [Message] to the thread that collects [Message]s and saves them to the
+    /// trace file.
+    #[inline(always)]
+    fn with_elapsed_micros_subtracting_tracing(&self, f: impl Fn(f64, usize, &Sender<Message>)) {
+        THREAD_DATA.with(|value| {
+            let mut thread_data = value.borrow_mut();
+            let (ThreadData { tid, out, start }, new_thread) = match thread_data.as_mut() {
+                Some(thread_data) => (thread_data, false),
+                None => {
+                    let tid = self.max_tid.fetch_add(1, Ordering::SeqCst);
+                    let out = self.out.lock().unwrap().clone();
+                    let start = TracingChromeInstant::setup_for_thread_and_start(tid);
+                    *thread_data = Some(ThreadData { tid, out, start });
+                    (thread_data.as_mut().unwrap(), true)
+                }
+            };
 
-    fn send_message(&self, message: Message) {
-        OUT.with(move |val| {
-            if val.borrow().is_some() {
-                let _ignored = val.borrow().as_ref().unwrap().send(message);
-            } else {
-                let out = self.out.lock().unwrap().clone();
-                let _ignored = out.send(message);
-                val.replace(Some(out));
-            }
+            start.with_elapsed_micros_subtracting_tracing(|ts| {
+                if new_thread {
+                    let name = match std::thread::current().name() {
+                        Some(name) => name.to_owned(),
+                        None => tid.to_string(),
+                    };
+                    let _ignored = out.send(Message::NewThread(*tid, name));
+                }
+                f(ts, *tid, out);
+            });
         });
     }
 }
@@ -586,52 +600,58 @@ where
             return;
         }
 
-        let ts = self.get_ts();
-        self.enter_span(ctx.span(id).expect("Span not found."), ts);
+        self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| {
+            self.enter_span(ctx.span(id).expect("Span not found."), ts, tid, out);
+        });
     }
 
     fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
         if self.include_args {
-            let span = ctx.span(id).unwrap();
-            let mut exts = span.extensions_mut();
+            self.with_elapsed_micros_subtracting_tracing(|_, _, _| {
+                let span = ctx.span(id).unwrap();
+                let mut exts = span.extensions_mut();
 
-            let args = exts.get_mut::<ArgsWrapper>();
+                let args = exts.get_mut::<ArgsWrapper>();
 
-            if let Some(args) = args {
-                let args = Arc::make_mut(&mut args.args);
-                values.record(&mut JsonVisitor { object: args });
-            }
+                if let Some(args) = args {
+                    let args = Arc::make_mut(&mut args.args);
+                    values.record(&mut JsonVisitor { object: args });
+                }
+            });
         }
     }
 
     fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
-        let ts = self.get_ts();
-        let callsite = self.get_callsite(EventOrSpan::Event(event));
-        self.send_message(Message::Event(ts, callsite));
+        self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| {
+            let callsite = self.get_callsite(EventOrSpan::Event(event), tid);
+            let _ignored = out.send(Message::Event(ts, callsite));
+        });
     }
 
     fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
         if let TraceStyle::Async = self.trace_style {
             return;
         }
-        let ts = self.get_ts();
-        self.exit_span(ctx.span(id).expect("Span not found."), ts);
+        self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| {
+            self.exit_span(ctx.span(id).expect("Span not found."), ts, tid, out);
+        });
     }
 
     fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
-        if self.include_args {
-            let mut args = Object::new();
-            attrs.record(&mut JsonVisitor { object: &mut args });
-            ctx.span(id).unwrap().extensions_mut().insert(ArgsWrapper {
-                args: Arc::new(args),
-            });
-        }
-        if let TraceStyle::Threaded = self.trace_style {
-            return;
-        }
+        self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| {
+            if self.include_args {
+                let mut args = Object::new();
+                attrs.record(&mut JsonVisitor { object: &mut args });
+                ctx.span(id).unwrap().extensions_mut().insert(ArgsWrapper {
+                    args: Arc::new(args),
+                });
+            }
+            if let TraceStyle::Threaded = self.trace_style {
+                return;
+            }
 
-        let ts = self.get_ts();
-        self.enter_span(ctx.span(id).expect("Span not found."), ts);
+            self.enter_span(ctx.span(id).expect("Span not found."), ts, tid, out);
+        });
     }
 
     fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
@@ -639,8 +659,9 @@ where
             return;
         }
 
-        let ts = self.get_ts();
-        self.exit_span(ctx.span(&id).expect("Span not found."), ts);
+        self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| {
+            self.exit_span(ctx.span(&id).expect("Span not found."), ts, tid, out);
+        });
     }
 }
 
diff --git a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs
new file mode 100644
index 00000000000..f400bc20a7b
--- /dev/null
+++ b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs
@@ -0,0 +1,183 @@
+//! Code in this class was in part inspired by
+//! <https://github.com/tikv/minstant/blob/27c9ec5ec90b5b67113a748a4defee0d2519518c/src/tsc_now.rs>.
+//! A useful resource is also
+//! <https://www.pingcap.com/blog/how-we-trace-a-kv-database-with-less-than-5-percent-performance-impact/>,
+//! although this file does not implement TSC synchronization but insteads pins threads to CPUs,
+//! since the former is not reliable (i.e. it might lead to non-monotonic time measurements).
+//! Another useful resource for future improvements might be measureme's time measurement utils:
+//! <https://github.com/rust-lang/measureme/blob/master/measureme/src/counters.rs>.
+//! Documentation about how the Linux kernel chooses a clock source can be found here:
+//! <https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/>.
+#![cfg(feature = "tracing")]
+
+/// This alternative `TracingChromeInstant` implementation was made entirely to suit the needs of
+/// [crate::log::tracing_chrome], and shouldn't be used for anything else. It featues two functions:
+/// - [TracingChromeInstant::setup_for_thread_and_start], which sets up the current thread to do
+///   proper time tracking and returns a point in time to use as "t=0", and
+/// - [TracingChromeInstant::with_elapsed_micros_subtracting_tracing], which allows
+///   obtaining how much time elapsed since [TracingChromeInstant::setup_for_thread_and_start] was
+///   called while accounting for (and subtracting) the time spent inside tracing-related functions.
+///
+/// This measures time using [std::time::Instant], except for x86/x86_64 Linux machines, where
+/// [std::time::Instant] is too slow (~1.5us) and thus `rdtsc` is used instead (~5ns).
+pub enum TracingChromeInstant {
+    WallTime {
+        /// The time at which this instant was created, shifted forward to account
+        /// for time spent in tracing functions as explained in
+        /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments.
+        start_instant: std::time::Instant,
+    },
+    #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))]
+    Tsc {
+        /// The value in the TSC counter when this instant was created, shifted forward to account
+        /// for time spent in tracing functions as explained in
+        /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments.
+        start_tsc: u64,
+        /// The period of the TSC counter in microseconds.
+        tsc_to_microseconds: f64,
+    },
+}
+
+impl TracingChromeInstant {
+    /// Can be thought of as the same as [std::time::Instant::now()], but also does some setup to
+    /// make TSC stable in case TSC is available. This is supposed to be called (at most) once per
+    /// thread since the thread setup takes a few milliseconds.
+    ///
+    /// WARNING: If TSC is available, `incremental_thread_id` is used to pick to which CPU to pin
+    /// the current thread. Thread IDs should be assigned contiguously starting from 0. Be aware
+    /// that the current thread will be restricted to one CPU for the rest of the execution!
+    pub fn setup_for_thread_and_start(incremental_thread_id: usize) -> TracingChromeInstant {
+        #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))]
+        if *tsc::IS_TSC_AVAILABLE.get_or_init(tsc::is_tsc_available) {
+            // We need to lock this thread to a specific CPU, because CPUs' TSC timers might be out
+            // of sync.
+            tsc::set_cpu_affinity(incremental_thread_id);
+
+            // Can only use tsc_to_microseconds() and rdtsc() after having set the CPU affinity!
+            // We compute tsc_to_microseconds anew for every new thread just in case some CPU core
+            // has a different TSC frequency.
+            let tsc_to_microseconds = tsc::tsc_to_microseconds();
+            let start_tsc = tsc::rdtsc();
+            return TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds };
+        }
+
+        let _ = incremental_thread_id; // otherwise we get a warning when the TSC branch is disabled
+        TracingChromeInstant::WallTime { start_instant: std::time::Instant::now() }
+    }
+
+    /// Calls `f` with the time elapsed in microseconds since this [TracingChromeInstant] was built
+    /// by [TracingChromeInstant::setup_for_thread_and_start], while subtracting all time previously
+    /// spent executing other `f`s passed to this function. This behavior allows subtracting time
+    /// spent in functions that log tracing data (which `f` is supposed to be) from the tracing time
+    /// measurements.
+    ///
+    /// Note: microseconds are used as the time unit since that's what Chrome trace files should
+    /// contain, see the definition of the "ts" field in
+    /// <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview>.
+    #[inline(always)]
+    pub fn with_elapsed_micros_subtracting_tracing(&mut self, f: impl Fn(f64)) {
+        match self {
+            TracingChromeInstant::WallTime { start_instant } => {
+                // Obtain the current time (before executing `f`).
+                let instant_before_f = std::time::Instant::now();
+
+                // Using the current time (`instant_before_f`) and the `start_instant` stored in
+                // `self`, calculate the elapsed time (in microseconds) since this instant was
+                // instantiated, accounting for any time that was previously spent executing `f`.
+                // The "accounting" part is not computed in this line, but is rather done by
+                // shifting forward the `start_instant` down below.
+                let ts = (instant_before_f - *start_instant).as_nanos() as f64 / 1000.0;
+
+                // Run the function (supposedly a function internal to the tracing infrastructure).
+                f(ts);
+
+                // Measure how much time was spent executing `f` and shift `start_instant` forward
+                // by that amount. This "removes" that time from the trace.
+                *start_instant += std::time::Instant::now() - instant_before_f;
+            }
+
+            #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))]
+            TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds } => {
+                // the comments above also apply here, since it's the same logic
+                let tsc_before_f = tsc::rdtsc();
+                let ts = ((tsc_before_f - *start_tsc) as f64) * (*tsc_to_microseconds);
+                f(ts);
+                *start_tsc += tsc::rdtsc() - tsc_before_f;
+            }
+        }
+    }
+}
+
+#[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))]
+mod tsc {
+
+    pub static IS_TSC_AVAILABLE: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
+
+    /// Reads the timestamp-counter register. Will give monotonic answers only when called from the
+    /// same thread, because the TSC of different CPUs might be out of sync.
+    #[inline(always)]
+    pub(super) fn rdtsc() -> u64 {
+        #[cfg(target_arch = "x86")]
+        use core::arch::x86::_rdtsc;
+        #[cfg(target_arch = "x86_64")]
+        use core::arch::x86_64::_rdtsc;
+
+        unsafe { _rdtsc() }
+    }
+
+    /// Estimates the frequency of the TSC counter by waiting 10ms in a busy loop and
+    /// looking at how much the TSC increased in the meantime.
+    pub(super) fn tsc_to_microseconds() -> f64 {
+        const BUSY_WAIT: std::time::Duration = std::time::Duration::from_millis(10);
+        let tsc_start = rdtsc();
+        let instant_start = std::time::Instant::now();
+        while instant_start.elapsed() < BUSY_WAIT {
+            // `thread::sleep()` is not very precise at waking up the program at the right time,
+            // so use a busy loop instead.
+            core::hint::spin_loop();
+        }
+        let tsc_end = rdtsc();
+        (BUSY_WAIT.as_nanos() as f64) / 1000.0 / ((tsc_end - tsc_start) as f64)
+    }
+
+    /// Checks whether the TSC counter is available and runs at a constant rate independently
+    /// of CPU frequency even across different power states of the CPU (i.e. checks for the
+    /// `invariant_tsc` CPUID flag).
+    pub(super) fn is_tsc_available() -> bool {
+        #[cfg(target_arch = "x86")]
+        use core::arch::x86::__cpuid;
+        #[cfg(target_arch = "x86_64")]
+        use core::arch::x86_64::__cpuid;
+
+        // implemented like https://docs.rs/raw-cpuid/latest/src/raw_cpuid/extended.rs.html#965-967
+        const LEAF: u32 = 0x80000007; // this is the leaf for "advanced power management info"
+        let cpuid = unsafe { __cpuid(LEAF) };
+        (cpuid.edx & (1 << 8)) != 0 // EDX bit 8 indicates invariant TSC
+    }
+
+    /// Forces the current thread to run on a single CPU, which ensures the TSC counter is monotonic
+    /// (since TSCs of different CPUs might be out-of-sync). `incremental_thread_id` is used to pick
+    /// to which CPU to pin the current thread, and should be an incremental number that starts from
+    /// 0.
+    pub(super) fn set_cpu_affinity(incremental_thread_id: usize) {
+        let cpu_id = match std::thread::available_parallelism() {
+            Ok(available_parallelism) => incremental_thread_id % available_parallelism,
+            _ => panic!("Could not determine CPU count to properly set CPU affinity"),
+        };
+
+        let mut set = unsafe { std::mem::zeroed::<libc::cpu_set_t>() };
+        unsafe { libc::CPU_SET(cpu_id, &mut set) };
+
+        // Set the current thread's core affinity.
+        if unsafe {
+            libc::sched_setaffinity(
+                0, // Defaults to current thread
+                size_of::<libc::cpu_set_t>(),
+                &set as *const _,
+            )
+        } != 0
+        {
+            panic!("Could not set CPU affinity")
+        }
+    }
+}
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index ae1b25f8857..9b0bee72aef 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -556,7 +556,11 @@ fn main() {
         } else if arg == "-Zmiri-deterministic-floats" {
             miri_config.float_nondet = false;
         } else if arg == "-Zmiri-no-extra-rounding-error" {
-            miri_config.float_rounding_error = false;
+            miri_config.float_rounding_error = miri::FloatRoundingErrorMode::None;
+        } else if arg == "-Zmiri-max-extra-rounding-error" {
+            miri_config.float_rounding_error = miri::FloatRoundingErrorMode::Max;
+        } else if arg == "-Zmiri-no-short-fd-operations" {
+            miri_config.short_fd_operations = false;
         } else if arg == "-Zmiri-strict-provenance" {
             miri_config.provenance_mode = ProvenanceMode::Strict;
         } else if arg == "-Zmiri-permissive-provenance" {
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 ad2a67160f4..bed65440dc9 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -125,81 +125,64 @@ pub struct NewPermission {
     /// Whether a read access should be performed on the non-frozen
     /// part on a retag.
     nonfreeze_access: bool,
+    /// Permission for memory outside the range.
+    outside_perm: Permission,
     /// Whether this pointer is part of the arguments of a function call.
     /// `protector` is `Some(_)` for all pointers marked `noalias`.
     protector: Option<ProtectorKind>,
 }
 
 impl<'tcx> NewPermission {
-    /// Determine NewPermission of the reference from the type of the pointee.
-    fn from_ref_ty(
+    /// Determine NewPermission of the reference/Box from the type of the pointee.
+    ///
+    /// A `ref_mutability` of `None` indicates a `Box` type.
+    fn new(
         pointee: Ty<'tcx>,
-        mutability: Mutability,
-        kind: RetagKind,
+        ref_mutability: Option<Mutability>,
+        retag_kind: RetagKind,
         cx: &crate::MiriInterpCx<'tcx>,
     ) -> Option<Self> {
         let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env());
-        let is_protected = kind == RetagKind::FnEntry;
-        let protector = is_protected.then_some(ProtectorKind::StrongProtector);
-
-        Some(match mutability {
-            Mutability::Mut if ty_is_unpin =>
-                NewPermission {
-                    freeze_perm: Permission::new_reserved(
-                        /* ty_is_freeze */ true,
-                        is_protected,
-                    ),
-                    freeze_access: true,
-                    nonfreeze_perm: Permission::new_reserved(
-                        /* ty_is_freeze */ false,
-                        is_protected,
-                    ),
-                    // If we have a mutable reference, then the non-frozen part will
-                    // have state `ReservedIM` or `Reserved`, which can have an initial read access
-                    // performed on it because you cannot have multiple mutable borrows.
-                    nonfreeze_access: true,
-                    protector,
-                },
-            Mutability::Not =>
-                NewPermission {
-                    freeze_perm: Permission::new_frozen(),
-                    freeze_access: true,
-                    nonfreeze_perm: Permission::new_cell(),
-                    // If it is a shared reference, then the non-frozen
-                    // part will have state `Cell`, which should not have an initial access,
-                    // as this can cause data races when using thread-safe data types like
-                    // `Mutex<T>`.
-                    nonfreeze_access: false,
-                    protector,
-                },
-            _ => return None,
-        })
-    }
+        let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
+        let is_protected = retag_kind == RetagKind::FnEntry;
 
-    /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled).
-    /// These pointers allow deallocation so need a different kind of protector not handled
-    /// by `from_ref_ty`.
-    fn from_unique_ty(
-        ty: Ty<'tcx>,
-        kind: RetagKind,
-        cx: &crate::MiriInterpCx<'tcx>,
-    ) -> Option<Self> {
-        let pointee = ty.builtin_deref(true).unwrap();
-        pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| {
-            // Regular `Unpin` box, give it `noalias` but only a weak protector
-            // because it is valid to deallocate it within the function.
-            let is_protected = kind == RetagKind::FnEntry;
-            let protector = is_protected.then_some(ProtectorKind::WeakProtector);
-            NewPermission {
-                freeze_perm: Permission::new_reserved(/* ty_is_freeze */ true, is_protected),
-                freeze_access: true,
-                nonfreeze_perm: Permission::new_reserved(
-                    /* ty_is_freeze */ false,
-                    is_protected,
-                ),
-                nonfreeze_access: true,
-                protector,
-            }
+        if matches!(ref_mutability, Some(Mutability::Mut) | None if !ty_is_unpin) {
+            // Mutable reference / Box to pinning type: retagging is a NOP.
+            // FIXME: with `UnsafePinned`, this should do proper per-byte tracking.
+            return None;
+        }
+
+        let freeze_perm = match ref_mutability {
+            // Shared references are frozen.
+            Some(Mutability::Not) => Permission::new_frozen(),
+            // Mutable references and Boxes are reserved.
+            _ => Permission::new_reserved_frz(),
+        };
+        let nonfreeze_perm = match ref_mutability {
+            // Shared references are "transparent".
+            Some(Mutability::Not) => Permission::new_cell(),
+            // *Protected* mutable references and boxes are reserved without regarding for interior mutability.
+            _ if is_protected => Permission::new_reserved_frz(),
+            // Unprotected mutable references and boxes start in `ReservedIm`.
+            _ => Permission::new_reserved_im(),
+        };
+
+        // Everything except for `Cell` gets an initial access.
+        let initial_access = |perm: &Permission| !perm.is_cell();
+
+        Some(NewPermission {
+            freeze_perm,
+            freeze_access: initial_access(&freeze_perm),
+            nonfreeze_perm,
+            nonfreeze_access: initial_access(&nonfreeze_perm),
+            outside_perm: if ty_is_freeze { freeze_perm } else { nonfreeze_perm },
+            protector: is_protected.then_some(if ref_mutability.is_some() {
+                // Strong protector for references
+                ProtectorKind::StrongProtector
+            } else {
+                // Weak protector for boxes
+                ProtectorKind::WeakProtector
+            }),
         })
     }
 }
@@ -313,30 +296,20 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let span = this.machine.current_span();
 
-        // Store initial permissions and their corresponding range.
-        let mut perms_map: DedupRangeMap<LocationState> = DedupRangeMap::new(
-            ptr_size,
-            LocationState::new_accessed(Permission::new_disabled(), IdempotentForeignAccess::None), // this will be overwritten
-        );
-        // Keep track of whether the node has any part that allows for interior mutability.
-        // FIXME: This misses `PhantomData<UnsafeCell<T>>` which could be considered a marker
-        // for requesting interior mutability.
-        let mut has_unsafe_cell = false;
-
         // When adding a new node, the SIFA of its parents needs to be updated, potentially across
         // the entire memory range. For the parts that are being accessed below, the access itself
-        // trivially takes care of that. However, we have to do some more work to also deal with
-        // the parts that are not being accessed. Specifically what we do is that we
-        // call `update_last_accessed_after_retag` on the SIFA of the permission set for the part of
-        // memory outside `perm_map` -- so that part is definitely taken care of. The remaining concern
-        // is the part of memory that is in the range of `perms_map`, but not accessed below.
-        // There we have two cases:
-        // * If we do have an `UnsafeCell` (`has_unsafe_cell` becomes true), then the non-accessed part
-        //   uses `nonfreeze_perm`, so the `nonfreeze_perm` initialized parts are also fine. We enforce
-        //   the `freeze_perm` parts to be accessed, and thus everything is taken care of.
-        // * If there is no `UnsafeCell`, then `freeze_perm` is used everywhere (both inside and outside the initial range),
-        //   and we update everything to have the `freeze_perm`'s SIFA, so there are no issues. (And this assert below is not
-        //   actually needed in this case).
+        // trivially takes care of that. However, we have to do some more work to also deal with the
+        // parts that are not being accessed. Specifically what we do is that we call
+        // `update_last_accessed_after_retag` on the SIFA of the permission set for the part of
+        // memory outside `perm_map` -- so that part is definitely taken care of. The remaining
+        // concern is the part of memory that is in the range of `perms_map`, but not accessed
+        // below. There we have two cases:
+        // * If the type is `!Freeze`, then the non-accessed part uses `nonfreeze_perm`, so the
+        //   `nonfreeze_perm` initialized parts are also fine. We enforce the `freeze_perm` parts to
+        //   be accessed via the assert below, and thus everything is taken care of.
+        // * If the type is `Freeze`, then `freeze_perm` is used everywhere (both inside and outside
+        //   the initial range), and we update everything to have the `freeze_perm`'s SIFA, so there
+        //   are no issues. (And this assert below is not actually needed in this case).
         assert!(new_perm.freeze_access);
 
         let protected = new_perm.protector.is_some();
@@ -350,66 +323,48 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             .get_tree_borrows_params()
             .precise_interior_mut;
 
-        let default_perm = if !precise_interior_mut {
-            // NOTE: Using `ty_is_freeze` doesn't give the same result as going through the range
-            // and computing `has_unsafe_cell`.  This is because of zero-sized `UnsafeCell`, for which
-            // `has_unsafe_cell` is false, but `!ty_is_freeze` is true.
-            let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env());
-            let (perm, access) = if ty_is_freeze {
+        // Compute initial "inside" permissions.
+        let loc_state = |frozen: bool| -> LocationState {
+            let (perm, access) = if frozen {
                 (new_perm.freeze_perm, new_perm.freeze_access)
             } else {
                 (new_perm.nonfreeze_perm, new_perm.nonfreeze_access)
             };
             let sifa = perm.strongest_idempotent_foreign_access(protected);
-            let new_loc = if access {
+            if access {
                 LocationState::new_accessed(perm, sifa)
             } else {
                 LocationState::new_non_accessed(perm, sifa)
-            };
-
-            for (_loc_range, loc) in perms_map.iter_mut_all() {
-                *loc = new_loc;
             }
-
-            perm
+        };
+        let perms_map = if !precise_interior_mut {
+            // For `!Freeze` types, just pretend the entire thing is an `UnsafeCell`.
+            let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env());
+            let state = loc_state(ty_is_freeze);
+            DedupRangeMap::new(ptr_size, state)
         } else {
+            // The initial state will be overwritten by the visitor below.
+            let mut perms_map: DedupRangeMap<LocationState> = DedupRangeMap::new(
+                ptr_size,
+                LocationState::new_accessed(
+                    Permission::new_disabled(),
+                    IdempotentForeignAccess::None,
+                ),
+            );
             this.visit_freeze_sensitive(place, ptr_size, |range, frozen| {
-                has_unsafe_cell = has_unsafe_cell || !frozen;
-
-                // We are only ever `Frozen` inside the frozen bits.
-                let (perm, access) = if frozen {
-                    (new_perm.freeze_perm, new_perm.freeze_access)
-                } else {
-                    (new_perm.nonfreeze_perm, new_perm.nonfreeze_access)
-                };
-                let sifa = perm.strongest_idempotent_foreign_access(protected);
-                // NOTE: Currently, `access` is false if and only if `perm` is Cell, so this `if`
-                // doesn't not change whether any code is UB or not. We could just always use
-                // `new_accessed` and everything would stay the same. But that seems conceptually
-                // odd, so we keep the initial "accessed" bit of the `LocationState` in sync with whether
-                // a read access is performed below.
-                let new_loc = if access {
-                    LocationState::new_accessed(perm, sifa)
-                } else {
-                    LocationState::new_non_accessed(perm, sifa)
-                };
-
-                // Store initial permissions.
+                let state = loc_state(frozen);
                 for (_loc_range, loc) in perms_map.iter_mut(range.start, range.size) {
-                    *loc = new_loc;
+                    *loc = state;
                 }
-
                 interp_ok(())
             })?;
-
-            // Allow lazily writing to surrounding data if we found an `UnsafeCell`.
-            if has_unsafe_cell { new_perm.nonfreeze_perm } else { new_perm.freeze_perm }
+            perms_map
         };
 
         let alloc_extra = this.get_alloc_extra(alloc_id)?;
         let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
 
-        for (perm_range, perm) in perms_map.iter_mut_all() {
+        for (perm_range, perm) in perms_map.iter_all() {
             if perm.is_accessed() {
                 // Some reborrows incur a read access to the parent.
                 // Adjust range to be relative to allocation start (rather than to `place`).
@@ -447,7 +402,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             orig_tag,
             new_tag,
             perms_map,
-            default_perm,
+            new_perm.outside_perm,
             protected,
             span,
         )?;
@@ -514,7 +469,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let new_perm = match val.layout.ty.kind() {
             &ty::Ref(_, pointee, mutability) =>
-                NewPermission::from_ref_ty(pointee, mutability, kind, this),
+                NewPermission::new(pointee, Some(mutability), kind, this),
             _ => None,
         };
         if let Some(new_perm) = new_perm {
@@ -571,8 +526,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> {
                 // Only boxes for the global allocator get any special treatment.
                 if box_ty.is_box_global(*self.ecx.tcx) {
+                    let pointee = place.layout.ty.builtin_deref(true).unwrap();
                     let new_perm =
-                        NewPermission::from_unique_ty(place.layout.ty, self.kind, self.ecx);
+                        NewPermission::new(pointee, /* not a ref */ None, self.kind, self.ecx);
                     self.retag_ptr_inplace(place, new_perm)?;
                 }
                 interp_ok(())
@@ -591,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 match place.layout.ty.kind() {
                     &ty::Ref(_, pointee, mutability) => {
                         let new_perm =
-                            NewPermission::from_ref_ty(pointee, mutability, self.kind, self.ecx);
+                            NewPermission::new(pointee, Some(mutability), self.kind, self.ecx);
                         self.retag_ptr_inplace(place, new_perm)?;
                     }
                     ty::RawPtr(_, _) => {
@@ -643,14 +599,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // never be ReservedIM, the value of the `ty_is_freeze`
             // argument doesn't matter
             // (`ty_is_freeze || true` in `new_reserved` will always be `true`).
-            freeze_perm: Permission::new_reserved(
-                /* ty_is_freeze */ true, /* protected */ true,
-            ),
+            freeze_perm: Permission::new_reserved_frz(),
             freeze_access: true,
-            nonfreeze_perm: Permission::new_reserved(
-                /* ty_is_freeze */ false, /* protected */ true,
-            ),
+            nonfreeze_perm: Permission::new_reserved_frz(),
             nonfreeze_access: true,
+            outside_perm: Permission::new_reserved_frz(),
             protector: Some(ProtectorKind::StrongProtector),
         };
         this.tb_retag_place(place, new_perm)
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 38863ca0734..390435e58d1 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -272,28 +272,15 @@ impl Permission {
 
     /// Default initial permission of a reborrowed mutable reference that is either
     /// protected or not interior mutable.
-    fn new_reserved_frz() -> Self {
+    pub fn new_reserved_frz() -> Self {
         Self { inner: ReservedFrz { conflicted: false } }
     }
 
     /// Default initial permission of an unprotected interior mutable reference.
-    fn new_reserved_im() -> Self {
+    pub fn new_reserved_im() -> Self {
         Self { inner: ReservedIM }
     }
 
-    /// Wrapper around `new_reserved_frz` and `new_reserved_im` that decides
-    /// which to call based on the interior mutability and the retag kind (whether there
-    /// is a protector is relevant because being protected takes priority over being
-    /// interior mutable)
-    pub fn new_reserved(ty_is_freeze: bool, protected: bool) -> Self {
-        // 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" in their reservation phase.
-        if ty_is_freeze || protected { Self::new_reserved_frz() } else { Self::new_reserved_im() }
-    }
-
     /// Default initial permission of a reborrowed shared reference.
     pub fn new_frozen() -> Self {
         Self { inner: Frozen }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index bb3fc2d80b3..d9b3696e4f8 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -610,7 +610,7 @@ mod spurious_read {
             },
             y: LocStateProt {
                 state: LocationState::new_non_accessed(
-                    Permission::new_reserved(/* freeze */ true, /* protected */ true),
+                    Permission::new_reserved_frz(),
                     IdempotentForeignAccess::default(),
                 ),
                 prot: true,
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 4c531a8d1f5..caed98f04f3 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -32,65 +32,6 @@ pub enum MiriEntryFnType {
 /// will hang the program.
 const MAIN_THREAD_YIELDS_AT_SHUTDOWN: u32 = 256;
 
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum AlignmentCheck {
-    /// Do not check alignment.
-    None,
-    /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address.
-    Symbolic,
-    /// Check alignment on the actual physical integer address.
-    Int,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum RejectOpWith {
-    /// Isolated op is rejected with an abort of the machine.
-    Abort,
-
-    /// If not Abort, miri returns an error for an isolated op.
-    /// Following options determine if user should be warned about such error.
-    /// Do not print warning about rejected isolated op.
-    NoWarning,
-
-    /// Print a warning about rejected isolated op, with backtrace.
-    Warning,
-
-    /// Print a warning about rejected isolated op, without backtrace.
-    WarningWithoutBacktrace,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum IsolatedOp {
-    /// Reject an op requiring communication with the host. By
-    /// default, miri rejects the op with an abort. If not, it returns
-    /// an error code, and prints a warning about it. Warning levels
-    /// are controlled by `RejectOpWith` enum.
-    Reject(RejectOpWith),
-
-    /// Execute op requiring communication with the host, i.e. disable isolation.
-    Allow,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum BacktraceStyle {
-    /// Prints a terser backtrace which ideally only contains relevant information.
-    Short,
-    /// Prints a backtrace with all possible information.
-    Full,
-    /// Prints only the frame that the error occurs in.
-    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 {
@@ -171,7 +112,9 @@ pub struct MiriConfig {
     /// Whether floating-point operations can behave non-deterministically.
     pub float_nondet: bool,
     /// Whether floating-point operations can have a non-deterministic rounding error.
-    pub float_rounding_error: bool,
+    pub float_rounding_error: FloatRoundingErrorMode,
+    /// Whether Miri artifically introduces short reads/writes on file descriptors.
+    pub short_fd_operations: bool,
 }
 
 impl Default for MiriConfig {
@@ -213,7 +156,8 @@ impl Default for MiriConfig {
             fixed_scheduling: false,
             force_intrinsic_fallback: false,
             float_nondet: true,
-            float_rounding_error: true,
+            float_rounding_error: FloatRoundingErrorMode::Random,
+            short_fd_operations: true,
         }
     }
 }
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index b5e81460773..4628c30e2df 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -3,20 +3,16 @@
 mod atomic;
 mod simd;
 
-use std::ops::Neg;
-
 use rand::Rng;
 use rustc_abi::Size;
-use rustc_apfloat::ieee::{IeeeFloat, Semantics};
 use rustc_apfloat::{self, Float, Round};
 use rustc_middle::mir;
-use rustc_middle::ty::{self, FloatTy, ScalarInt};
+use rustc_middle::ty::{self, FloatTy};
 use rustc_span::{Symbol, sym};
 
 use self::atomic::EvalContextExt as _;
 use self::helpers::{ToHost, ToSoft};
 use self::simd::EvalContextExt as _;
-use crate::math::{IeeeExt, apply_random_float_error_ulp};
 use crate::*;
 
 /// Check that the number of args is what we expect.
@@ -209,7 +205,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f] = check_intrinsic_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
 
-                let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
+                let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, these operations do not have
                     // guaranteed precision).
                     let host = f.to_host();
@@ -227,15 +223,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    let res = apply_random_float_error_ulp(
+                    let res = math::apply_random_float_error_ulp(
                         this,
                         res,
-                        2, // log2(4)
+                        4,
                     );
 
                     // Clamp the result to the guaranteed range of this function according to the C standard,
                     // if any.
-                    clamp_float_value(intrinsic_name, res)
+                    math::clamp_float_value(intrinsic_name, res)
                 });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
@@ -253,7 +249,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f] = check_intrinsic_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
 
-                let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
+                let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, these operations do not have
                     // guaranteed precision).
                     let host = f.to_host();
@@ -271,15 +267,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    let res = apply_random_float_error_ulp(
+                    let res = math::apply_random_float_error_ulp(
                         this,
                         res,
-                        2, // log2(4)
+                        4,
                     );
 
                     // Clamp the result to the guaranteed range of this function according to the C standard,
                     // if any.
-                    clamp_float_value(intrinsic_name, res)
+                    math::clamp_float_value(intrinsic_name, res)
                 });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
@@ -330,16 +326,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f1 = this.read_scalar(f1)?.to_f32()?;
                 let f2 = this.read_scalar(f2)?.to_f32()?;
 
-                let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
-                    // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                    let res = f1.to_host().powf(f2.to_host()).to_soft();
+                let res =
+                    math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+                        // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                        let res = f1.to_host().powf(f2.to_host()).to_soft();
 
-                    // Apply a relative error of 4ULP to introduce some non-determinism
-                    // simulating imprecise implementations and optimizations.
-                    apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    )
-                });
+                        // Apply a relative error of 4ULP to introduce some non-determinism
+                        // simulating imprecise implementations and optimizations.
+                        math::apply_random_float_error_ulp(this, res, 4)
+                    });
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -348,16 +343,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f1 = this.read_scalar(f1)?.to_f64()?;
                 let f2 = this.read_scalar(f2)?.to_f64()?;
 
-                let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
-                    // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                    let res = f1.to_host().powf(f2.to_host()).to_soft();
+                let res =
+                    math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+                        // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                        let res = f1.to_host().powf(f2.to_host()).to_soft();
 
-                    // Apply a relative error of 4ULP to introduce some non-determinism
-                    // simulating imprecise implementations and optimizations.
-                    apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    )
-                });
+                        // Apply a relative error of 4ULP to introduce some non-determinism
+                        // simulating imprecise implementations and optimizations.
+                        math::apply_random_float_error_ulp(this, res, 4)
+                    });
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -367,15 +361,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f = this.read_scalar(f)?.to_f32()?;
                 let i = this.read_scalar(i)?.to_i32()?;
 
-                let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
+                let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f.to_host().powi(i).to_soft();
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    )
+                    math::apply_random_float_error_ulp(this, res, 4)
                 });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
@@ -385,15 +377,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f = this.read_scalar(f)?.to_f64()?;
                 let i = this.read_scalar(i)?.to_i32()?;
 
-                let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
+                let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f.to_host().powi(i).to_soft();
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    )
+                    math::apply_random_float_error_ulp(this, res, 4)
                 });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
@@ -448,7 +438,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
                 // Apply a relative error of 4ULP to simulate non-deterministic precision loss
                 // due to optimizations.
-                let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?;
+                let res = math::apply_random_float_error_to_imm(this, res, 4)?;
                 this.write_immediate(*res, dest)?;
             }
 
@@ -485,133 +475,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
-
-/// Applies a random ULP floating point error to `val` and returns the new value.
-/// So if you want an X ULP error, `ulp_exponent` should be log2(X).
-///
-/// Will fail if `val` is not a floating point number.
-fn apply_random_float_error_to_imm<'tcx>(
-    ecx: &mut MiriInterpCx<'tcx>,
-    val: ImmTy<'tcx>,
-    ulp_exponent: u32,
-) -> InterpResult<'tcx, ImmTy<'tcx>> {
-    let scalar = val.to_scalar_int()?;
-    let res: ScalarInt = match val.layout.ty.kind() {
-        ty::Float(FloatTy::F16) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(),
-        ty::Float(FloatTy::F32) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(),
-        ty::Float(FloatTy::F64) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(),
-        ty::Float(FloatTy::F128) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(),
-        _ => bug!("intrinsic called with non-float input type"),
-    };
-
-    interp_ok(ImmTy::from_scalar_int(res, val.layout))
-}
-
-/// For the intrinsics:
-/// - sinf32, sinf64
-/// - cosf32, cosf64
-/// - expf32, expf64, exp2f32, exp2f64
-/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
-/// - powf32, powf64
-///
-/// # Return
-///
-/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
-/// (specifically, C23 annex F.10)  when given `args` as arguments. Outputs that are unaffected by a relative error
-/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
-/// implementation. Returns `None` if no specific value is guaranteed.
-///
-/// # Note
-///
-/// For `powf*` operations of the form:
-///
-/// - `(SNaN)^(±0)`
-/// - `1^(SNaN)`
-///
-/// The result is implementation-defined:
-/// - musl returns for both `1.0`
-/// - glibc returns for both `NaN`
-///
-/// This discrepancy exists because SNaN handling is not consistently defined across platforms,
-/// and the C standard leaves behavior for SNaNs unspecified.
-///
-/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
-fn fixed_float_value<S: Semantics>(
-    ecx: &mut MiriInterpCx<'_>,
-    intrinsic_name: &str,
-    args: &[IeeeFloat<S>],
-) -> Option<IeeeFloat<S>> {
-    let one = IeeeFloat::<S>::one();
-    Some(match (intrinsic_name, args) {
-        // cos(+- 0) = 1
-        ("cosf32" | "cosf64", [input]) if input.is_zero() => one,
-
-        // e^0 = 1
-        ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
-
-        // (-1)^(±INF) = 1
-        ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
-
-        // 1^y = 1 for any y, even a NaN
-        ("powf32" | "powf64", [base, exp]) if *base == one => {
-            let rng = ecx.machine.rng.get_mut();
-            // SNaN exponents get special treatment: they might return 1, or a NaN.
-            let return_nan = exp.is_signaling() && ecx.machine.float_nondet && rng.random();
-            // Handle both the musl and glibc cases non-deterministically.
-            if return_nan { ecx.generate_nan(args) } else { one }
-        }
-
-        // x^(±0) = 1 for any x, even a NaN
-        ("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
-            let rng = ecx.machine.rng.get_mut();
-            // SNaN bases get special treatment: they might return 1, or a NaN.
-            let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random();
-            // Handle both the musl and glibc cases non-deterministically.
-            if return_nan { ecx.generate_nan(args) } else { one }
-        }
-
-        // There are a lot of cases for fixed outputs according to the C Standard, but these are
-        // mainly INF or zero which are not affected by the applied error.
-        _ => return None,
-    })
-}
-
-/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
-/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
-fn fixed_powi_float_value<S: Semantics>(
-    ecx: &mut MiriInterpCx<'_>,
-    base: IeeeFloat<S>,
-    exp: i32,
-) -> Option<IeeeFloat<S>> {
-    Some(match exp {
-        0 => {
-            let one = IeeeFloat::<S>::one();
-            let rng = ecx.machine.rng.get_mut();
-            let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
-            // For SNaN treatment, we are consistent with `powf`above.
-            // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
-            // but for now we are maximally conservative.)
-            if return_nan { ecx.generate_nan(&[base]) } else { one }
-        }
-
-        _ => return None,
-    })
-}
-
-/// Given an floating-point operation and a floating-point value, clamps the result to the output
-/// range of the given operation.
-fn clamp_float_value<S: Semantics>(intrinsic_name: &str, val: IeeeFloat<S>) -> IeeeFloat<S> {
-    match intrinsic_name {
-        // sin and cos: [-1, 1]
-        "sinf32" | "cosf32" | "sinf64" | "cosf64" =>
-            val.clamp(IeeeFloat::<S>::one().neg(), IeeeFloat::<S>::one()),
-        // exp: [0, +INF]
-        "expf32" | "exp2f32" | "expf64" | "exp2f64" =>
-            IeeeFloat::<S>::maximum(val, IeeeFloat::<S>::ZERO),
-        _ => val,
-    }
-}
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 5ed6d6b346c..0856411b8e8 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -138,15 +138,14 @@ pub use crate::data_structures::mono_hash_map::MonoHashMap;
 pub use crate::diagnostics::{
     EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error,
 };
-pub use crate::eval::{
-    AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith,
-    ValidationMode, create_ecx, eval_entry,
-};
+pub use crate::eval::{MiriConfig, MiriEntryFnType, create_ecx, eval_entry};
 pub use crate::helpers::{AccessKind, EvalContextExt as _, ToU64 as _, ToUsize as _};
 pub use crate::intrinsics::EvalContextExt as _;
 pub use crate::machine::{
-    AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx,
-    MiriInterpCxExt, MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra,
+    AlignmentCheck, AllocExtra, BacktraceStyle, DynMachineCallback, FloatRoundingErrorMode,
+    FrameExtra, IsolatedOp, MachineCallback, MemoryKind, MiriInterpCx, MiriInterpCxExt,
+    MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra, RejectOpWith,
+    ValidationMode,
 };
 pub use crate::operator::EvalContextExt as _;
 pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith};
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 0b2ce900414..e4540fb9bc5 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -49,6 +49,75 @@ pub const SIGRTMAX: i32 = 42;
 /// base address for each evaluation would produce unbounded memory usage.
 const ADDRS_PER_ANON_GLOBAL: usize = 32;
 
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum AlignmentCheck {
+    /// Do not check alignment.
+    None,
+    /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address.
+    Symbolic,
+    /// Check alignment on the actual physical integer address.
+    Int,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum RejectOpWith {
+    /// Isolated op is rejected with an abort of the machine.
+    Abort,
+
+    /// If not Abort, miri returns an error for an isolated op.
+    /// Following options determine if user should be warned about such error.
+    /// Do not print warning about rejected isolated op.
+    NoWarning,
+
+    /// Print a warning about rejected isolated op, with backtrace.
+    Warning,
+
+    /// Print a warning about rejected isolated op, without backtrace.
+    WarningWithoutBacktrace,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum IsolatedOp {
+    /// Reject an op requiring communication with the host. By
+    /// default, miri rejects the op with an abort. If not, it returns
+    /// an error code, and prints a warning about it. Warning levels
+    /// are controlled by `RejectOpWith` enum.
+    Reject(RejectOpWith),
+
+    /// Execute op requiring communication with the host, i.e. disable isolation.
+    Allow,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum BacktraceStyle {
+    /// Prints a terser backtrace which ideally only contains relevant information.
+    Short,
+    /// Prints a backtrace with all possible information.
+    Full,
+    /// Prints only the frame that the error occurs in.
+    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,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum FloatRoundingErrorMode {
+    /// Apply a random error (the default).
+    Random,
+    /// Don't apply any error.
+    None,
+    /// Always apply the maximum error (with a random sign).
+    Max,
+}
+
 /// Extra data stored with each stack frame
 pub struct FrameExtra<'tcx> {
     /// Extra data for the Borrow Tracker.
@@ -599,7 +668,10 @@ pub struct MiriMachine<'tcx> {
     /// Whether floating-point operations can behave non-deterministically.
     pub float_nondet: bool,
     /// Whether floating-point operations can have a non-deterministic rounding error.
-    pub float_rounding_error: bool,
+    pub float_rounding_error: FloatRoundingErrorMode,
+
+    /// Whether Miri artifically introduces short reads/writes on file descriptors.
+    pub short_fd_operations: bool,
 }
 
 impl<'tcx> MiriMachine<'tcx> {
@@ -761,6 +833,7 @@ impl<'tcx> MiriMachine<'tcx> {
             force_intrinsic_fallback: config.force_intrinsic_fallback,
             float_nondet: config.float_nondet,
             float_rounding_error: config.float_rounding_error,
+            short_fd_operations: config.short_fd_operations,
         }
     }
 
@@ -937,6 +1010,7 @@ impl VisitProvenance for MiriMachine<'_> {
             force_intrinsic_fallback: _,
             float_nondet: _,
             float_rounding_error: _,
+            short_fd_operations: _,
         } = self;
 
         threads.visit_provenance(visit);
@@ -1077,7 +1151,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                 .target_features
                 .iter()
                 .filter(|&feature| {
-                    feature.kind != TargetFeatureKind::Implied && !ecx.tcx.sess.target_features.contains(&feature.name)
+                    feature.kind != TargetFeatureKind::Implied
+                        && !ecx.tcx.sess.target_features.contains(&feature.name)
                 })
                 .fold(String::new(), |mut s, feature| {
                     if !s.is_empty() {
@@ -1208,7 +1283,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &mut InterpCx<'tcx, Self>,
         val: ImmTy<'tcx>,
     ) -> InterpResult<'tcx, ImmTy<'tcx>> {
-        crate::math::apply_random_float_error_to_imm(ecx, val, 2 /* log2(4) */)
+        crate::math::apply_random_float_error_to_imm(ecx, val, 4)
     }
 
     #[inline(always)]
diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs
index e9e5a1070c9..7d2f1c08368 100644
--- a/src/tools/miri/src/math.rs
+++ b/src/tools/miri/src/math.rs
@@ -1,78 +1,317 @@
+use std::ops::Neg;
+use std::{f32, f64};
+
 use rand::Rng as _;
 use rustc_apfloat::Float as _;
-use rustc_apfloat::ieee::IeeeFloat;
+use rustc_apfloat::ieee::{DoubleS, IeeeFloat, Semantics, SingleS};
 use rustc_middle::ty::{self, FloatTy, ScalarInt};
 
 use crate::*;
 
 /// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale).
-///
-/// For a 2^N ULP error, you can use an `err_scale` of `-(F::PRECISION - 1 - N)`.
-/// In other words, a 1 ULP (absolute) error is the same as a `2^-(F::PRECISION-1)` relative error.
-/// (Subtracting 1 compensates for the integer bit.)
 pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
     ecx: &mut crate::MiriInterpCx<'_>,
     val: F,
     err_scale: i32,
 ) -> F {
-    if !ecx.machine.float_nondet || !ecx.machine.float_rounding_error {
+    if !ecx.machine.float_nondet
+        || matches!(ecx.machine.float_rounding_error, FloatRoundingErrorMode::None)
+        // relative errors don't do anything to zeros... avoid messing up the sign
+        || val.is_zero()
+        // The logic below makes no sense if the input is already non-finite.
+        || !val.is_finite()
+    {
         return val;
     }
-
     let rng = ecx.machine.rng.get_mut();
+
     // Generate a random integer in the range [0, 2^PREC).
     // (When read as binary, the position of the first `1` determines the exponent,
     // and the remaining bits fill the mantissa. `PREC` is one plus the size of the mantissa,
     // so this all works out.)
-    let r = F::from_u128(rng.random_range(0..(1 << F::PRECISION))).value;
+    let r = F::from_u128(match ecx.machine.float_rounding_error {
+        FloatRoundingErrorMode::Random => rng.random_range(0..(1 << F::PRECISION)),
+        FloatRoundingErrorMode::Max => (1 << F::PRECISION) - 1, // force max error
+        FloatRoundingErrorMode::None => unreachable!(),
+    })
+    .value;
     // Multiply this with 2^(scale - PREC). The result is between 0 and
     // 2^PREC * 2^(scale - PREC) = 2^scale.
     let err = r.scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap()));
     // give it a random sign
     let err = if rng.random() { -err } else { err };
-    // multiple the value with (1+err)
-    (val * (F::from_u128(1).value + err).value).value
+    // Compute `val*(1+err)`, distributed out as `val + val*err` to avoid the imprecise addition
+    // error being amplified by multiplication.
+    (val + (val * err).value).value
 }
 
-/// [`apply_random_float_error`] gives instructions to apply a 2^N ULP error.
-/// This function implements these instructions such that applying a 2^N ULP error is less error prone.
-/// So for a 2^N ULP error, you would pass N as the `ulp_exponent` argument.
+/// Applies an error of `[-N, +N]` ULP to the given value.
 pub(crate) fn apply_random_float_error_ulp<F: rustc_apfloat::Float>(
     ecx: &mut crate::MiriInterpCx<'_>,
     val: F,
-    ulp_exponent: u32,
+    max_error: u32,
 ) -> F {
-    let n = i32::try_from(ulp_exponent)
-        .expect("`err_scale_for_ulp`: exponent is too large to create an error scale");
-    // we know this fits
-    let prec = i32::try_from(F::PRECISION).unwrap();
-    let err_scale = -(prec - n - 1);
-    apply_random_float_error(ecx, val, err_scale)
+    // We could try to be clever and reuse `apply_random_float_error`, but that is hard to get right
+    // (see <https://github.com/rust-lang/miri/pull/4558#discussion_r2316838085> for why) so we
+    // implement the logic directly instead.
+    if !ecx.machine.float_nondet
+        || matches!(ecx.machine.float_rounding_error, FloatRoundingErrorMode::None)
+        // FIXME: also disturb zeros? That requires a lot more cases in `fixed_float_value`
+        // and might make the std test suite quite unhappy.
+        || val.is_zero()
+        // The logic below makes no sense if the input is already non-finite.
+        || !val.is_finite()
+    {
+        return val;
+    }
+    let rng = ecx.machine.rng.get_mut();
+
+    let max_error = i64::from(max_error);
+    let error = match ecx.machine.float_rounding_error {
+        FloatRoundingErrorMode::Random => rng.random_range(-max_error..=max_error),
+        FloatRoundingErrorMode::Max =>
+            if rng.random() {
+                max_error
+            } else {
+                -max_error
+            },
+        FloatRoundingErrorMode::None => unreachable!(),
+    };
+    // If upwards ULP and downwards ULP differ, we take the average.
+    let ulp = (((val.next_up().value - val).value + (val - val.next_down().value).value).value
+        / F::from_u128(2).value)
+        .value;
+    // Shift the value by N times the ULP
+    (val + (ulp * F::from_i128(error.into()).value).value).value
 }
 
-/// Applies a random 16ULP floating point error to `val` and returns the new value.
+/// Applies an error of `[-N, +N]` ULP to the given value.
 /// Will fail if `val` is not a floating point number.
 pub(crate) fn apply_random_float_error_to_imm<'tcx>(
     ecx: &mut MiriInterpCx<'tcx>,
     val: ImmTy<'tcx>,
-    ulp_exponent: u32,
+    max_error: u32,
 ) -> InterpResult<'tcx, ImmTy<'tcx>> {
     let scalar = val.to_scalar_int()?;
     let res: ScalarInt = match val.layout.ty.kind() {
         ty::Float(FloatTy::F16) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f16(), max_error).into(),
         ty::Float(FloatTy::F32) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f32(), max_error).into(),
         ty::Float(FloatTy::F64) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f64(), max_error).into(),
         ty::Float(FloatTy::F128) =>
-            apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f128(), max_error).into(),
         _ => bug!("intrinsic called with non-float input type"),
     };
 
     interp_ok(ImmTy::from_scalar_int(res, val.layout))
 }
 
+/// Given a floating-point operation and a floating-point value, clamps the result to the output
+/// range of the given operation according to the C standard, if any.
+pub(crate) fn clamp_float_value<S: Semantics>(
+    intrinsic_name: &str,
+    val: IeeeFloat<S>,
+) -> IeeeFloat<S>
+where
+    IeeeFloat<S>: IeeeExt,
+{
+    let zero = IeeeFloat::<S>::ZERO;
+    let one = IeeeFloat::<S>::one();
+    let two = IeeeFloat::<S>::two();
+    let pi = IeeeFloat::<S>::pi();
+    let pi_over_2 = (pi / two).value;
+
+    match intrinsic_name {
+        // sin, cos, tanh: [-1, 1]
+        #[rustfmt::skip]
+        | "sinf32"
+        | "sinf64"
+        | "cosf32"
+        | "cosf64"
+        | "tanhf"
+        | "tanh"
+         => val.clamp(one.neg(), one),
+
+        // exp: [0, +INF)
+        "expf32" | "exp2f32" | "expf64" | "exp2f64" => val.maximum(zero),
+
+        // cosh: [1, +INF)
+        "coshf" | "cosh" => val.maximum(one),
+
+        // acos: [0, π]
+        "acosf" | "acos" => val.clamp(zero, pi),
+
+        // asin: [-π, +π]
+        "asinf" | "asin" => val.clamp(pi.neg(), pi),
+
+        // atan: (-π/2, +π/2)
+        "atanf" | "atan" => val.clamp(pi_over_2.neg(), pi_over_2),
+
+        // erfc: (-1, 1)
+        "erff" | "erf" => val.clamp(one.neg(), one),
+
+        // erfc: (0, 2)
+        "erfcf" | "erfc" => val.clamp(zero, two),
+
+        // atan2(y, x): arctan(y/x) in [−π, +π]
+        "atan2f" | "atan2" => val.clamp(pi.neg(), pi),
+
+        _ => val,
+    }
+}
+
+/// For the intrinsics:
+/// - sinf32, sinf64, sinhf, sinh
+/// - cosf32, cosf64, coshf, cosh
+/// - tanhf, tanh, atanf, atan, atan2f, atan2
+/// - expf32, expf64, exp2f32, exp2f64
+/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
+/// - powf32, powf64
+/// - erff, erf, erfcf, erfc
+/// - hypotf, hypot
+///
+/// # Return
+///
+/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
+/// (specifically, C23 annex F.10)  when given `args` as arguments. Outputs that are unaffected by a relative error
+/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
+/// implementation. Returns `None` if no specific value is guaranteed.
+///
+/// # Note
+///
+/// For `powf*` operations of the form:
+///
+/// - `(SNaN)^(±0)`
+/// - `1^(SNaN)`
+///
+/// The result is implementation-defined:
+/// - musl returns for both `1.0`
+/// - glibc returns for both `NaN`
+///
+/// This discrepancy exists because SNaN handling is not consistently defined across platforms,
+/// and the C standard leaves behavior for SNaNs unspecified.
+///
+/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
+pub(crate) fn fixed_float_value<S: Semantics>(
+    ecx: &mut MiriInterpCx<'_>,
+    intrinsic_name: &str,
+    args: &[IeeeFloat<S>],
+) -> Option<IeeeFloat<S>>
+where
+    IeeeFloat<S>: IeeeExt,
+{
+    let this = ecx.eval_context_mut();
+    let one = IeeeFloat::<S>::one();
+    let two = IeeeFloat::<S>::two();
+    let three = IeeeFloat::<S>::three();
+    let pi = IeeeFloat::<S>::pi();
+    let pi_over_2 = (pi / two).value;
+    let pi_over_4 = (pi_over_2 / two).value;
+
+    Some(match (intrinsic_name, args) {
+        // cos(±0) and cosh(±0)= 1
+        ("cosf32" | "cosf64" | "coshf" | "cosh", [input]) if input.is_zero() => one,
+
+        // e^0 = 1
+        ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
+
+        // tanh(±INF) = ±1
+        ("tanhf" | "tanh", [input]) if input.is_infinite() => one.copy_sign(*input),
+
+        // atan(±INF) = ±π/2
+        ("atanf" | "atan", [input]) if input.is_infinite() => pi_over_2.copy_sign(*input),
+
+        // erf(±INF) = ±1
+        ("erff" | "erf", [input]) if input.is_infinite() => one.copy_sign(*input),
+
+        // erfc(-INF) = 2
+        ("erfcf" | "erfc", [input]) if input.is_neg_infinity() => (one + one).value,
+
+        // hypot(x, ±0) = abs(x), if x is not a NaN.
+        ("_hypotf" | "hypotf" | "_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() =>
+            x.abs(),
+
+        // atan2(±0,−0) = ±π.
+        // atan2(±0, y) = ±π for y < 0.
+        // Must check for non NaN because `y.is_negative()` also applies to NaN.
+        ("atan2f" | "atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) =>
+            pi.copy_sign(*x),
+
+        // atan2(±x,−∞) = ±π for finite x > 0.
+        ("atan2f" | "atan2", [x, y])
+            if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() =>
+            pi.copy_sign(*x),
+
+        // atan2(x, ±0) = −π/2 for x < 0.
+        // atan2(x, ±0) =  π/2 for x > 0.
+        ("atan2f" | "atan2", [x, y]) if !x.is_zero() && y.is_zero() => pi_over_2.copy_sign(*x),
+
+        //atan2(±∞, −∞) = ±3π/4
+        ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_neg_infinity() =>
+            (pi_over_4 * three).value.copy_sign(*x),
+
+        //atan2(±∞, +∞) = ±π/4
+        ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() =>
+            pi_over_4.copy_sign(*x),
+
+        // atan2(±∞, y) returns ±π/2 for finite y.
+        ("atan2f" | "atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) =>
+            pi_over_2.copy_sign(*x),
+
+        // (-1)^(±INF) = 1
+        ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
+
+        // 1^y = 1 for any y, even a NaN
+        ("powf32" | "powf64", [base, exp]) if *base == one => {
+            let rng = this.machine.rng.get_mut();
+            // SNaN exponents get special treatment: they might return 1, or a NaN.
+            let return_nan = exp.is_signaling() && this.machine.float_nondet && rng.random();
+            // Handle both the musl and glibc cases non-deterministically.
+            if return_nan { this.generate_nan(args) } else { one }
+        }
+
+        // x^(±0) = 1 for any x, even a NaN
+        ("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
+            let rng = this.machine.rng.get_mut();
+            // SNaN bases get special treatment: they might return 1, or a NaN.
+            let return_nan = base.is_signaling() && this.machine.float_nondet && rng.random();
+            // Handle both the musl and glibc cases non-deterministically.
+            if return_nan { this.generate_nan(args) } else { one }
+        }
+
+        // There are a lot of cases for fixed outputs according to the C Standard, but these are
+        // mainly INF or zero which are not affected by the applied error.
+        _ => return None,
+    })
+}
+
+/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
+/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
+pub(crate) fn fixed_powi_value<S: Semantics>(
+    ecx: &mut MiriInterpCx<'_>,
+    base: IeeeFloat<S>,
+    exp: i32,
+) -> Option<IeeeFloat<S>>
+where
+    IeeeFloat<S>: IeeeExt,
+{
+    match exp {
+        0 => {
+            let one = IeeeFloat::<S>::one();
+            let rng = ecx.machine.rng.get_mut();
+            let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
+            // For SNaN treatment, we are consistent with `powf`above.
+            // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
+            // but for now we are maximally conservative.)
+            Some(if return_nan { ecx.generate_nan(&[base]) } else { one })
+        }
+
+        _ => return None,
+    }
+}
+
 pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFloat<S> {
     match x.category() {
         // preserve zero sign
@@ -155,19 +394,47 @@ pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFl
     }
 }
 
-/// Extend functionality of rustc_apfloat softfloats
+/// Extend functionality of `rustc_apfloat` softfloats for IEEE float types.
 pub trait IeeeExt: rustc_apfloat::Float {
+    // Some values we use:
+
     #[inline]
     fn one() -> Self {
         Self::from_u128(1).value
     }
 
     #[inline]
+    fn two() -> Self {
+        Self::from_u128(2).value
+    }
+
+    #[inline]
+    fn three() -> Self {
+        Self::from_u128(3).value
+    }
+
+    fn pi() -> Self;
+
+    #[inline]
     fn clamp(self, min: Self, max: Self) -> Self {
         self.maximum(min).minimum(max)
     }
 }
-impl<S: rustc_apfloat::ieee::Semantics> IeeeExt for IeeeFloat<S> {}
+
+macro_rules! impl_ieee_pi {
+    ($float_ty:ident, $semantic:ty) => {
+        impl IeeeExt for IeeeFloat<$semantic> {
+            #[inline]
+            fn pi() -> Self {
+                // We take the value from the standard library as the most reasonable source for an exact π here.
+                Self::from_bits($float_ty::consts::PI.to_bits().into())
+            }
+        }
+    };
+}
+
+impl_ieee_pi!(f32, SingleS);
+impl_ieee_pi!(f64, DoubleS);
 
 #[cfg(test)]
 mod tests {
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index 0d4642c6ad0..8c29cb040b5 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -168,8 +168,9 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
     }
 
     /// Determines whether this FD non-deterministically has its reads and writes shortened.
-    fn nondet_short_accesses(&self) -> bool {
-        true
+    fn short_fd_operations(&self) -> bool {
+        // We only enable this for FD kinds where we think short accesses gain useful test coverage.
+        false
     }
 
     /// Seeks to the given offset (which can be relative to the beginning, end, or current position).
@@ -395,6 +396,13 @@ impl FileDescription for FileHandle {
         communicate_allowed && self.file.is_terminal()
     }
 
+    fn short_fd_operations(&self) -> bool {
+        // While short accesses on file-backed FDs are very rare (at least for sufficiently small
+        // accesses), they can realistically happen when a signal interrupts the syscall.
+        // FIXME: we should return `false` if this is a named pipe...
+        true
+    }
+
     fn as_unix<'tcx>(&self, ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         assert!(
             ecx.target_os_is_unix(),
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index a700644b95d..187423472ab 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -18,6 +18,7 @@ use rustc_target::callconv::FnAbi;
 use self::helpers::{ToHost, ToSoft};
 use super::alloc::EvalContextExt as _;
 use super::backtrace::EvalContextExt as _;
+use crate::helpers::EvalContextExt as _;
 use crate::*;
 
 /// Type of dynamic symbols (for `dlsym` et al)
@@ -826,33 +827,36 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             => {
                 let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
-                // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                let f_host = f.to_host();
-                let res = match link_name.as_str() {
-                    "cbrtf" => f_host.cbrt(),
-                    "coshf" => f_host.cosh(),
-                    "sinhf" => f_host.sinh(),
-                    "tanf" => f_host.tan(),
-                    "tanhf" => f_host.tanh(),
-                    "acosf" => f_host.acos(),
-                    "asinf" => f_host.asin(),
-                    "atanf" => f_host.atan(),
-                    "log1pf" => f_host.ln_1p(),
-                    "expm1f" => f_host.exp_m1(),
-                    "tgammaf" => f_host.gamma(),
-                    "erff" => f_host.erf(),
-                    "erfcf" => f_host.erfc(),
-                    _ => bug!(),
-                };
-                let res = res.to_soft();
-                // Apply a relative error of 16ULP to introduce some non-determinism
-                // simulating imprecise implementations and optimizations.
-                // FIXME: temporarily disabled as it breaks std tests.
-                // let res = math::apply_random_float_error_ulp(
-                //     this,
-                //     res,
-                //     4, // log2(16)
-                // );
+
+                let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
+                    // Using host floats (but it's fine, these operations do not have
+                    // guaranteed precision).
+                    let f_host = f.to_host();
+                    let res = match link_name.as_str() {
+                        "cbrtf" => f_host.cbrt(),
+                        "coshf" => f_host.cosh(),
+                        "sinhf" => f_host.sinh(),
+                        "tanf" => f_host.tan(),
+                        "tanhf" => f_host.tanh(),
+                        "acosf" => f_host.acos(),
+                        "asinf" => f_host.asin(),
+                        "atanf" => f_host.atan(),
+                        "log1pf" => f_host.ln_1p(),
+                        "expm1f" => f_host.exp_m1(),
+                        "tgammaf" => f_host.gamma(),
+                        "erff" => f_host.erf(),
+                        "erfcf" => f_host.erfc(),
+                        _ => bug!(),
+                    };
+                    let res = res.to_soft();
+                    // Apply a relative error of 4ULP to introduce some non-determinism
+                    // simulating imprecise implementations and optimizations.
+                    let res = math::apply_random_float_error_ulp(this, res, 4);
+
+                    // Clamp the result to the guaranteed range of this function according to the C standard,
+                    // if any.
+                    math::clamp_float_value(link_name.as_str(), res)
+                });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
@@ -865,24 +869,27 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f32()?;
                 let f2 = this.read_scalar(f2)?.to_f32()?;
-                // underscore case for windows, here and below
-                // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
-                // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                let res = match link_name.as_str() {
-                    "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
-                    "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
-                    #[allow(deprecated)]
-                    "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
-                    _ => bug!(),
-                };
-                // Apply a relative error of 16ULP to introduce some non-determinism
-                // simulating imprecise implementations and optimizations.
-                // FIXME: temporarily disabled as it breaks std tests.
-                // let res = math::apply_random_float_error_ulp(
-                //     this,
-                //     res,
-                //     4, // log2(16)
-                // );
+
+                let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2])
+                    .unwrap_or_else(|| {
+                        let res = match link_name.as_str() {
+                            // underscore case for windows, here and below
+                            // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
+                            // Using host floats (but it's fine, these operations do not have guaranteed precision).
+                            "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
+                            "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
+                            #[allow(deprecated)]
+                            "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
+                            _ => bug!(),
+                        };
+                        // Apply a relative error of 4ULP to introduce some non-determinism
+                        // simulating imprecise implementations and optimizations.
+                        let res = math::apply_random_float_error_ulp(this, res, 4);
+
+                        // Clamp the result to the guaranteed range of this function according to the C standard,
+                        // if any.
+                        math::clamp_float_value(link_name.as_str(), res)
+                    });
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -903,33 +910,36 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             => {
                 let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
-                // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                let f_host = f.to_host();
-                let res = match link_name.as_str() {
-                    "cbrt" => f_host.cbrt(),
-                    "cosh" => f_host.cosh(),
-                    "sinh" => f_host.sinh(),
-                    "tan" => f_host.tan(),
-                    "tanh" => f_host.tanh(),
-                    "acos" => f_host.acos(),
-                    "asin" => f_host.asin(),
-                    "atan" => f_host.atan(),
-                    "log1p" => f_host.ln_1p(),
-                    "expm1" => f_host.exp_m1(),
-                    "tgamma" => f_host.gamma(),
-                    "erf" => f_host.erf(),
-                    "erfc" => f_host.erfc(),
-                    _ => bug!(),
-                };
-                let res = res.to_soft();
-                // Apply a relative error of 16ULP to introduce some non-determinism
-                // simulating imprecise implementations and optimizations.
-                // FIXME: temporarily disabled as it breaks std tests.
-                // let res = math::apply_random_float_error_ulp(
-                //     this,
-                //     res.to_soft(),
-                //     4, // log2(16)
-                // );
+
+                let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
+                    // Using host floats (but it's fine, these operations do not have
+                    // guaranteed precision).
+                    let f_host = f.to_host();
+                    let res = match link_name.as_str() {
+                        "cbrt" => f_host.cbrt(),
+                        "cosh" => f_host.cosh(),
+                        "sinh" => f_host.sinh(),
+                        "tan" => f_host.tan(),
+                        "tanh" => f_host.tanh(),
+                        "acos" => f_host.acos(),
+                        "asin" => f_host.asin(),
+                        "atan" => f_host.atan(),
+                        "log1p" => f_host.ln_1p(),
+                        "expm1" => f_host.exp_m1(),
+                        "tgamma" => f_host.gamma(),
+                        "erf" => f_host.erf(),
+                        "erfc" => f_host.erfc(),
+                        _ => bug!(),
+                    };
+                    let res = res.to_soft();
+                    // Apply a relative error of 4ULP to introduce some non-determinism
+                    // simulating imprecise implementations and optimizations.
+                    let res = math::apply_random_float_error_ulp(this, res, 4);
+
+                    // Clamp the result to the guaranteed range of this function according to the C standard,
+                    // if any.
+                    math::clamp_float_value(link_name.as_str(), res)
+                });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
@@ -942,24 +952,26 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f64()?;
                 let f2 = this.read_scalar(f2)?.to_f64()?;
-                // underscore case for windows, here and below
-                // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
-                // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                let res = match link_name.as_str() {
-                    "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
-                    "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
-                    #[allow(deprecated)]
-                    "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
-                    _ => bug!(),
-                };
-                // Apply a relative error of 16ULP to introduce some non-determinism
-                // simulating imprecise implementations and optimizations.
-                // FIXME: temporarily disabled as it breaks std tests.
-                // let res = math::apply_random_float_error_ulp(
-                //     this,
-                //     res,
-                //     4, // log2(16)
-                // );
+
+                let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| {
+                    let res = match link_name.as_str() {
+                        // underscore case for windows, here and below
+                        // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
+                        // Using host floats (but it's fine, these operations do not have guaranteed precision).
+                        "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
+                        "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
+                        #[allow(deprecated)]
+                        "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
+                        _ => bug!(),
+                    };
+                    // Apply a relative error of 4ULP to introduce some non-determinism
+                    // simulating imprecise implementations and optimizations.
+                    let res = math::apply_random_float_error_ulp(this, res, 4);
+
+                    // Clamp the result to the guaranteed range of this function according to the C standard,
+                    // if any.
+                    math::clamp_float_value(link_name.as_str(), res)
+                });
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -985,11 +997,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let (res, sign) = x.to_host().ln_gamma();
                 this.write_int(sign, &signp)?;
+
                 let res = res.to_soft();
-                // Apply a relative error of 16ULP to introduce some non-determinism
+                // Apply a relative error of 4ULP to introduce some non-determinism
                 // simulating imprecise implementations and optimizations.
-                // FIXME: temporarily disabled as it breaks std tests.
-                // let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */);
+                let res = math::apply_random_float_error_ulp(this, res, 4);
+                // Clamp the result to the guaranteed range of this function according to the C standard,
+                // if any.
+                let res = math::clamp_float_value(link_name.as_str(), res);
                 let res = this.adjust_nan(res, &[x]);
                 this.write_scalar(res, dest)?;
             }
@@ -1001,11 +1016,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let (res, sign) = x.to_host().ln_gamma();
                 this.write_int(sign, &signp)?;
+
                 let res = res.to_soft();
-                // Apply a relative error of 16ULP to introduce some non-determinism
+                // Apply a relative error of 4ULP to introduce some non-determinism
                 // simulating imprecise implementations and optimizations.
-                // FIXME: temporarily disabled as it breaks std tests.
-                // let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */);
+                let res = math::apply_random_float_error_ulp(this, res, 4);
+                // Clamp the result to the guaranteed range of this function according to the C standard,
+                // if any.
+                let res = math::clamp_float_value(link_name.as_str(), res);
                 let res = this.adjust_nan(res, &[x]);
                 this.write_scalar(res, dest)?;
             }
diff --git a/src/tools/miri/src/shims/native_lib/ffi.rs b/src/tools/miri/src/shims/native_lib/ffi.rs
new file mode 100644
index 00000000000..0badf22bb76
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/ffi.rs
@@ -0,0 +1,46 @@
+//! Support code for dealing with libffi.
+
+use libffi::low::CodePtr;
+use libffi::middle::{Arg as ArgPtr, Cif, Type as FfiType};
+
+/// Perform the actual FFI call.
+///
+/// # Safety
+///
+/// The safety invariants of the foreign function being called must be upheld (if any).
+pub unsafe fn call<R: libffi::high::CType>(fun: CodePtr, args: &mut [OwnedArg]) -> R {
+    let arg_ptrs: Vec<_> = args.iter().map(|arg| arg.ptr()).collect();
+    let cif = Cif::new(args.iter_mut().map(|arg| arg.ty.take().unwrap()), R::reify().into_middle());
+    // SAFETY: Caller upholds that the function is safe to call, and since we
+    // were passed a slice reference we know the `OwnedArg`s won't have been
+    // dropped by this point.
+    unsafe { cif.call(fun, &arg_ptrs) }
+}
+
+/// An argument for an FFI call.
+#[derive(Debug, Clone)]
+pub struct OwnedArg {
+    /// The type descriptor for this argument.
+    ty: Option<FfiType>,
+    /// Corresponding bytes for the value.
+    bytes: Box<[u8]>,
+}
+
+impl OwnedArg {
+    /// Instantiates an argument from a type descriptor and bytes.
+    pub fn new(ty: FfiType, bytes: Box<[u8]>) -> Self {
+        Self { ty: Some(ty), bytes }
+    }
+
+    /// Creates a libffi argument pointer pointing to this argument's bytes.
+    /// NB: Since `libffi::middle::Arg` ignores the lifetime of the reference
+    /// it's derived from, it is up to the caller to ensure the `OwnedArg` is
+    /// not dropped before unsafely calling `libffi::middle::Cif::call()`!
+    fn ptr(&self) -> ArgPtr {
+        // FIXME: Using `&self.bytes[0]` to reference the whole array is
+        // definitely unsound under SB, but we're waiting on
+        // https://github.com/libffi-rs/libffi-rs/commit/112a37b3b6ffb35bd75241fbcc580de40ba74a73
+        // to land in a release so that we don't need to do this.
+        ArgPtr::new(&self.bytes[0])
+    }
+}
diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs
index 74b9b704fea..da8f785e373 100644
--- a/src/tools/miri/src/shims/native_lib/mod.rs
+++ b/src/tools/miri/src/shims/native_lib/mod.rs
@@ -2,14 +2,15 @@
 
 use std::ops::Deref;
 
-use libffi::high::call as ffi;
 use libffi::low::CodePtr;
-use rustc_abi::{BackendRepr, HasDataLayout, Size};
-use rustc_middle::mir::interpret::Pointer;
-use rustc_middle::ty::{self as ty, IntTy, UintTy};
+use libffi::middle::Type as FfiType;
+use rustc_abi::{HasDataLayout, Size};
+use rustc_middle::ty::{self as ty, IntTy, Ty, UintTy};
 use rustc_span::Symbol;
 use serde::{Deserialize, Serialize};
 
+mod ffi;
+
 #[cfg_attr(
     not(all(
         target_os = "linux",
@@ -20,6 +21,7 @@ use serde::{Deserialize, Serialize};
 )]
 pub mod trace;
 
+use self::ffi::OwnedArg;
 use crate::*;
 
 /// The final results of an FFI trace, containing every relevant event detected
@@ -70,12 +72,12 @@ impl AccessRange {
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Call native host function and return the output as an immediate.
-    fn call_native_with_args<'a>(
+    fn call_native_with_args(
         &mut self,
         link_name: Symbol,
         dest: &MPlaceTy<'tcx>,
-        ptr: CodePtr,
-        libffi_args: Vec<libffi::high::Arg<'a>>,
+        fun: CodePtr,
+        libffi_args: &mut [OwnedArg],
     ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option<MemEvents>)> {
         let this = self.eval_context_mut();
         #[cfg(target_os = "linux")]
@@ -93,55 +95,55 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // Unsafe because of the call to native code.
                     // Because this is calling a C function it is not necessarily sound,
                     // but there is no way around this and we've checked as much as we can.
-                    let x = unsafe { ffi::call::<i8>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<i8>(fun, libffi_args) };
                     Scalar::from_i8(x)
                 }
                 ty::Int(IntTy::I16) => {
-                    let x = unsafe { ffi::call::<i16>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<i16>(fun, libffi_args) };
                     Scalar::from_i16(x)
                 }
                 ty::Int(IntTy::I32) => {
-                    let x = unsafe { ffi::call::<i32>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<i32>(fun, libffi_args) };
                     Scalar::from_i32(x)
                 }
                 ty::Int(IntTy::I64) => {
-                    let x = unsafe { ffi::call::<i64>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<i64>(fun, libffi_args) };
                     Scalar::from_i64(x)
                 }
                 ty::Int(IntTy::Isize) => {
-                    let x = unsafe { ffi::call::<isize>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<isize>(fun, libffi_args) };
                     Scalar::from_target_isize(x.try_into().unwrap(), this)
                 }
                 // uints
                 ty::Uint(UintTy::U8) => {
-                    let x = unsafe { ffi::call::<u8>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<u8>(fun, libffi_args) };
                     Scalar::from_u8(x)
                 }
                 ty::Uint(UintTy::U16) => {
-                    let x = unsafe { ffi::call::<u16>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<u16>(fun, libffi_args) };
                     Scalar::from_u16(x)
                 }
                 ty::Uint(UintTy::U32) => {
-                    let x = unsafe { ffi::call::<u32>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<u32>(fun, libffi_args) };
                     Scalar::from_u32(x)
                 }
                 ty::Uint(UintTy::U64) => {
-                    let x = unsafe { ffi::call::<u64>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<u64>(fun, libffi_args) };
                     Scalar::from_u64(x)
                 }
                 ty::Uint(UintTy::Usize) => {
-                    let x = unsafe { ffi::call::<usize>(ptr, libffi_args.as_slice()) };
+                    let x = unsafe { ffi::call::<usize>(fun, libffi_args) };
                     Scalar::from_target_usize(x.try_into().unwrap(), this)
                 }
                 // Functions with no declared return type (i.e., the default return)
                 // have the output_type `Tuple([])`.
                 ty::Tuple(t_list) if (*t_list).deref().is_empty() => {
-                    unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
+                    unsafe { ffi::call::<()>(fun, libffi_args) };
                     return interp_ok(ImmTy::uninit(dest.layout));
                 }
                 ty::RawPtr(..) => {
-                    let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) };
-                    let ptr = Pointer::new(Provenance::Wildcard, Size::from_bytes(x.addr()));
+                    let x = unsafe { ffi::call::<*const ()>(fun, libffi_args) };
+                    let ptr = StrictPointer::new(Provenance::Wildcard, Size::from_bytes(x.addr()));
                     Scalar::from_pointer(ptr, this)
                 }
                 _ =>
@@ -267,6 +269,150 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         interp_ok(())
     }
+
+    /// Extract the value from the result of reading an operand from the machine
+    /// and convert it to a `OwnedArg`.
+    fn op_to_ffi_arg(&self, v: &OpTy<'tcx>, tracing: bool) -> InterpResult<'tcx, OwnedArg> {
+        let this = self.eval_context_ref();
+
+        // This should go first so that we emit unsupported before doing a bunch
+        // of extra work for types that aren't supported yet.
+        let ty = this.ty_to_ffitype(v.layout.ty)?;
+
+        // Helper to print a warning when a pointer is shared with the native code.
+        let expose = |prov: Provenance| -> InterpResult<'tcx> {
+            // The first time this happens, print a warning.
+            if !this.machine.native_call_mem_warned.replace(true) {
+                // Newly set, so first time we get here.
+                this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem { tracing });
+            }
+
+            this.expose_provenance(prov)?;
+            interp_ok(())
+        };
+
+        // Compute the byte-level representation of the argument. If there's a pointer in there, we
+        // expose it inside the AM. Later in `visit_reachable_allocs`, the "meta"-level provenance
+        // for accessing the pointee gets exposed; this is crucial to justify the C code effectively
+        // casting the integer in `byte` to a pointer and using that.
+        let bytes = match v.as_mplace_or_imm() {
+            either::Either::Left(mplace) => {
+                // Get the alloc id corresponding to this mplace, alongside
+                // a pointer that's offset to point to this particular
+                // mplace (not one at the base addr of the allocation).
+                let sz = mplace.layout.size.bytes_usize();
+                if sz == 0 {
+                    throw_unsup_format!("attempting to pass a ZST over FFI");
+                }
+                let (id, ofs, _) = this.ptr_get_alloc_id(mplace.ptr(), sz.try_into().unwrap())?;
+                let ofs = ofs.bytes_usize();
+                let range = ofs..ofs.strict_add(sz);
+                // Expose all provenances in the allocation within the byte range of the struct, if
+                // any. These pointers are being directly passed to native code by-value.
+                let alloc = this.get_alloc_raw(id)?;
+                for prov in alloc.provenance().get_range(this, range.clone().into()) {
+                    expose(prov)?;
+                }
+                // Read the bytes that make up this argument. We cannot use the normal getter as
+                // those would fail if any part of the argument is uninitialized. Native code
+                // is kind of outside the interpreter, after all...
+                Box::from(alloc.inspect_with_uninit_and_ptr_outside_interpreter(range))
+            }
+            either::Either::Right(imm) => {
+                let mut bytes: Box<[u8]> = vec![0; imm.layout.size.bytes_usize()].into();
+
+                // A little helper to write scalars to our byte array.
+                let mut write_scalar = |this: &MiriInterpCx<'tcx>, sc: Scalar, pos: usize| {
+                    // If a scalar is a pointer, then expose its provenance.
+                    if let interpret::Scalar::Ptr(p, _) = sc {
+                        expose(p.provenance)?;
+                    }
+                    write_target_uint(
+                        this.data_layout().endian,
+                        &mut bytes[pos..][..sc.size().bytes_usize()],
+                        sc.to_scalar_int()?.to_bits_unchecked(),
+                    )
+                    .unwrap();
+                    interp_ok(())
+                };
+
+                // Write the scalar into the `bytes` buffer.
+                match *imm {
+                    Immediate::Scalar(sc) => write_scalar(this, sc, 0)?,
+                    Immediate::ScalarPair(sc_first, sc_second) => {
+                        // The first scalar has an offset of zero; compute the offset of the 2nd.
+                        let ofs_second = {
+                            let rustc_abi::BackendRepr::ScalarPair(a, b) = imm.layout.backend_repr
+                            else {
+                                span_bug!(
+                                    this.cur_span(),
+                                    "op_to_ffi_arg: invalid scalar pair layout: {:#?}",
+                                    imm.layout
+                                )
+                            };
+                            a.size(this).align_to(b.align(this).abi).bytes_usize()
+                        };
+
+                        write_scalar(this, sc_first, 0)?;
+                        write_scalar(this, sc_second, ofs_second)?;
+                    }
+                    Immediate::Uninit => {
+                        // Nothing to write.
+                    }
+                }
+
+                bytes
+            }
+        };
+        interp_ok(OwnedArg::new(ty, bytes))
+    }
+
+    /// Parses an ADT to construct the matching libffi type.
+    fn adt_to_ffitype(
+        &self,
+        orig_ty: Ty<'_>,
+        adt_def: ty::AdtDef<'tcx>,
+        args: &'tcx ty::List<ty::GenericArg<'tcx>>,
+    ) -> InterpResult<'tcx, FfiType> {
+        // TODO: Certain non-C reprs should be okay also.
+        if !adt_def.repr().c() {
+            throw_unsup_format!("passing a non-#[repr(C)] struct over FFI: {orig_ty}")
+        }
+        // TODO: unions, etc.
+        if !adt_def.is_struct() {
+            throw_unsup_format!(
+                "unsupported argument type for native call: {orig_ty} is an enum or union"
+            );
+        }
+
+        let this = self.eval_context_ref();
+        let mut fields = vec![];
+        for field in &adt_def.non_enum_variant().fields {
+            fields.push(this.ty_to_ffitype(field.ty(*this.tcx, args))?);
+        }
+
+        interp_ok(FfiType::structure(fields))
+    }
+
+    /// Gets the matching libffi type for a given Ty.
+    fn ty_to_ffitype(&self, ty: Ty<'tcx>) -> InterpResult<'tcx, FfiType> {
+        interp_ok(match ty.kind() {
+            ty::Int(IntTy::I8) => FfiType::i8(),
+            ty::Int(IntTy::I16) => FfiType::i16(),
+            ty::Int(IntTy::I32) => FfiType::i32(),
+            ty::Int(IntTy::I64) => FfiType::i64(),
+            ty::Int(IntTy::Isize) => FfiType::isize(),
+            // the uints
+            ty::Uint(UintTy::U8) => FfiType::u8(),
+            ty::Uint(UintTy::U16) => FfiType::u16(),
+            ty::Uint(UintTy::U32) => FfiType::u32(),
+            ty::Uint(UintTy::U64) => FfiType::u64(),
+            ty::Uint(UintTy::Usize) => FfiType::usize(),
+            ty::RawPtr(..) => FfiType::pointer(),
+            ty::Adt(adt_def, args) => self.adt_to_ffitype(ty, *adt_def, args)?,
+            _ => throw_unsup_format!("unsupported argument type for native call: {}", ty),
+        })
+    }
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -295,36 +441,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Do we have ptrace?
         let tracing = trace::Supervisor::is_enabled();
 
-        // Get the function arguments, and convert them to `libffi`-compatible form.
-        let mut libffi_args = Vec::<CArg>::with_capacity(args.len());
+        // Get the function arguments, copy them, and prepare the type descriptions.
+        let mut libffi_args = Vec::<OwnedArg>::with_capacity(args.len());
         for arg in args.iter() {
-            if !matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) {
-                throw_unsup_format!("only scalar argument types are supported for native calls")
-            }
-            let imm = this.read_immediate(arg)?;
-            libffi_args.push(imm_to_carg(&imm, this)?);
-            // If we are passing a pointer, expose its provenance. Below, all exposed memory
-            // (previously exposed and new exposed) will then be properly prepared.
-            if matches!(arg.layout.ty.kind(), ty::RawPtr(..)) {
-                let ptr = imm.to_scalar().to_pointer(this)?;
-                let Some(prov) = ptr.provenance else {
-                    // Pointer without provenance may not access any memory anyway, skip.
-                    continue;
-                };
-                // The first time this happens, print a warning.
-                if !this.machine.native_call_mem_warned.replace(true) {
-                    // Newly set, so first time we get here.
-                    this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem { tracing });
-                }
-
-                this.expose_provenance(prov)?;
-            }
+            libffi_args.push(this.op_to_ffi_arg(arg, tracing)?);
         }
-        // Convert arguments to `libffi::high::Arg` type.
-        let libffi_args = libffi_args
-            .iter()
-            .map(|arg| arg.arg_downcast())
-            .collect::<Vec<libffi::high::Arg<'_>>>();
 
         // Prepare all exposed memory (both previously exposed, and just newly exposed since a
         // pointer was passed as argument). Uninitialised memory is left as-is, but any data
@@ -343,8 +464,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance());
 
             if !tracing {
-                // Expose all provenances in this allocation, since the native code can do $whatever.
-                // Can be skipped when tracing; in that case we'll expose just the actually-read parts later.
+                // Expose all provenances in this allocation, since the native code can do
+                // $whatever. Can be skipped when tracing; in that case we'll expose just the
+                // actually-read parts later.
                 for prov in alloc.provenance().provenances() {
                     this.expose_provenance(prov)?;
                 }
@@ -354,7 +476,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             if info.mutbl.is_mut() {
                 let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?;
                 // These writes could initialize everything and wreck havoc with the pointers.
-                // We can skip that when tracing; in that case we'll later do that only for the memory that got actually written.
+                // We can skip that when tracing; in that case we'll later do that only for the
+                // memory that got actually written.
                 if !tracing {
                     alloc.process_native_write(&cx.tcx, None);
                 }
@@ -367,7 +490,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Call the function and store output, depending on return type in the function signature.
         let (ret, maybe_memevents) =
-            this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
+            this.call_native_with_args(link_name, dest, code_ptr, &mut libffi_args)?;
 
         if tracing {
             this.tracing_apply_accesses(maybe_memevents.unwrap())?;
@@ -377,83 +500,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(true)
     }
 }
-
-#[derive(Debug, Clone)]
-/// Enum of supported arguments to external C functions.
-// We introduce this enum instead of just calling `ffi::arg` and storing a list
-// of `libffi::high::Arg` directly, because the `libffi::high::Arg` just wraps a reference
-// to the value it represents: https://docs.rs/libffi/latest/libffi/high/call/struct.Arg.html
-// and we need to store a copy of the value, and pass a reference to this copy to C instead.
-enum CArg {
-    /// 8-bit signed integer.
-    Int8(i8),
-    /// 16-bit signed integer.
-    Int16(i16),
-    /// 32-bit signed integer.
-    Int32(i32),
-    /// 64-bit signed integer.
-    Int64(i64),
-    /// isize.
-    ISize(isize),
-    /// 8-bit unsigned integer.
-    UInt8(u8),
-    /// 16-bit unsigned integer.
-    UInt16(u16),
-    /// 32-bit unsigned integer.
-    UInt32(u32),
-    /// 64-bit unsigned integer.
-    UInt64(u64),
-    /// usize.
-    USize(usize),
-    /// Raw pointer, stored as C's `void*`.
-    RawPtr(*mut std::ffi::c_void),
-}
-
-impl<'a> CArg {
-    /// Convert a `CArg` to a `libffi` argument type.
-    fn arg_downcast(&'a self) -> libffi::high::Arg<'a> {
-        match self {
-            CArg::Int8(i) => ffi::arg(i),
-            CArg::Int16(i) => ffi::arg(i),
-            CArg::Int32(i) => ffi::arg(i),
-            CArg::Int64(i) => ffi::arg(i),
-            CArg::ISize(i) => ffi::arg(i),
-            CArg::UInt8(i) => ffi::arg(i),
-            CArg::UInt16(i) => ffi::arg(i),
-            CArg::UInt32(i) => ffi::arg(i),
-            CArg::UInt64(i) => ffi::arg(i),
-            CArg::USize(i) => ffi::arg(i),
-            CArg::RawPtr(i) => ffi::arg(i),
-        }
-    }
-}
-
-/// Extract the scalar value from the result of reading a scalar from the machine,
-/// and convert it to a `CArg`.
-fn imm_to_carg<'tcx>(v: &ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'tcx, CArg> {
-    interp_ok(match v.layout.ty.kind() {
-        // If the primitive provided can be converted to a type matching the type pattern
-        // then create a `CArg` of this primitive value with the corresponding `CArg` constructor.
-        // the ints
-        ty::Int(IntTy::I8) => CArg::Int8(v.to_scalar().to_i8()?),
-        ty::Int(IntTy::I16) => CArg::Int16(v.to_scalar().to_i16()?),
-        ty::Int(IntTy::I32) => CArg::Int32(v.to_scalar().to_i32()?),
-        ty::Int(IntTy::I64) => CArg::Int64(v.to_scalar().to_i64()?),
-        ty::Int(IntTy::Isize) =>
-            CArg::ISize(v.to_scalar().to_target_isize(cx)?.try_into().unwrap()),
-        // the uints
-        ty::Uint(UintTy::U8) => CArg::UInt8(v.to_scalar().to_u8()?),
-        ty::Uint(UintTy::U16) => CArg::UInt16(v.to_scalar().to_u16()?),
-        ty::Uint(UintTy::U32) => CArg::UInt32(v.to_scalar().to_u32()?),
-        ty::Uint(UintTy::U64) => CArg::UInt64(v.to_scalar().to_u64()?),
-        ty::Uint(UintTy::Usize) =>
-            CArg::USize(v.to_scalar().to_target_usize(cx)?.try_into().unwrap()),
-        ty::RawPtr(..) => {
-            let s = v.to_scalar().to_pointer(cx)?.addr();
-            // This relies on the `expose_provenance` in the `visit_reachable_allocs` callback
-            // above.
-            CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize()))
-        }
-        _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty),
-    })
-}
diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs
index b998ba822dd..95b0617a026 100644
--- a/src/tools/miri/src/shims/native_lib/trace/child.rs
+++ b/src/tools/miri/src/shims/native_lib/trace/child.rs
@@ -90,14 +90,6 @@ impl Supervisor {
         // Unwinding might be messed up due to partly protected memory, so let's abort if something
         // breaks inside here.
         let res = std::panic::abort_unwind(|| {
-            // SAFETY: We do not access machine memory past this point until the
-            // supervisor is ready to allow it.
-            // FIXME: this is sketchy, as technically the memory is still in the Rust Abstract Machine,
-            // and the compiler would be allowed to reorder accesses below this block...
-            unsafe {
-                Self::protect_pages(alloc.pages(), mman::ProtFlags::PROT_NONE).unwrap();
-            }
-
             // Send over the info.
             // NB: if we do not wait to receive a blank confirmation response, it is
             // possible that the supervisor is alerted of the SIGSTOP *before* it has
@@ -110,16 +102,14 @@ impl Supervisor {
             // count.
             signal::raise(signal::SIGSTOP).unwrap();
 
-            let res = f();
+            // SAFETY: We have coordinated with the supervisor to ensure that this memory will keep
+            // working as normal, just with extra tracing. So even if the compiler moves memory
+            // accesses down to after the `mprotect`, they won't actually segfault.
+            unsafe {
+                Self::protect_pages(alloc.pages(), mman::ProtFlags::PROT_NONE).unwrap();
+            }
 
-            // We can't use IPC channels here to signal that FFI mode has ended,
-            // since they might allocate memory which could get us stuck in a SIGTRAP
-            // with no easy way out! While this could be worked around, it is much
-            // simpler and more robust to simply use the signals which are left for
-            // arbitrary usage. Since this will block until we are continued by the
-            // supervisor, we can assume past this point that everything is back to
-            // normal.
-            signal::raise(signal::SIGUSR1).unwrap();
+            let res = f();
 
             // SAFETY: We set memory back to normal, so this is safe.
             unsafe {
@@ -130,6 +120,12 @@ impl Supervisor {
                 .unwrap();
             }
 
+            // Signal the supervisor that we are done. Will block until the supervisor continues us.
+            // This will also shut down the segfault handler, so it's important that all memory is
+            // reset back to normal above. There must not be a window in time where accessing the
+            // pages we protected above actually causes the program to abort.
+            signal::raise(signal::SIGUSR1).unwrap();
+
             res
         });
 
diff --git a/src/tools/miri/src/shims/native_lib/trace/parent.rs b/src/tools/miri/src/shims/native_lib/trace/parent.rs
index 83f6c7a13fc..3ae98259ab3 100644
--- a/src/tools/miri/src/shims/native_lib/trace/parent.rs
+++ b/src/tools/miri/src/shims/native_lib/trace/parent.rs
@@ -18,6 +18,11 @@ const ARCH_WORD_SIZE: usize = 4;
 #[cfg(target_arch = "x86_64")]
 const ARCH_WORD_SIZE: usize = 8;
 
+// x86 max instruction length is 15 bytes:
+// https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
+// See vol. 3B section 24.25.
+const ARCH_MAX_INSTR_SIZE: usize = 15;
+
 /// The address of the page set to be edited, initialised to a sentinel null
 /// pointer.
 static PAGE_ADDR: AtomicPtr<u8> = AtomicPtr::new(std::ptr::null_mut());
@@ -132,10 +137,10 @@ impl Iterator for ChildListener {
                                 return Some(ExecEvent::Syscall(pid));
                             },
                         // Child with the given pid was stopped by the given signal.
-                        // It's somewhat dubious when this is returned instead of
-                        // WaitStatus::Stopped, but for our purposes they are the
-                        // same thing.
-                        wait::WaitStatus::PtraceEvent(pid, signal, _) =>
+                        // It's somewhat unclear when which of these two is returned;
+                        // we just treat them the same.
+                        wait::WaitStatus::Stopped(pid, signal)
+                        | wait::WaitStatus::PtraceEvent(pid, signal, _) =>
                             if self.attached {
                                 // This is our end-of-FFI signal!
                                 if signal == signal::SIGUSR1 {
@@ -148,19 +153,6 @@ impl Iterator for ChildListener {
                                 // Just pass along the signal.
                                 ptrace::cont(pid, signal).unwrap();
                             },
-                        // Child was stopped at the given signal. Same logic as for
-                        // WaitStatus::PtraceEvent.
-                        wait::WaitStatus::Stopped(pid, signal) =>
-                            if self.attached {
-                                if signal == signal::SIGUSR1 {
-                                    self.attached = false;
-                                    return Some(ExecEvent::End);
-                                } else {
-                                    return Some(ExecEvent::Status(pid, signal));
-                                }
-                            } else {
-                                ptrace::cont(pid, signal).unwrap();
-                            },
                         _ => (),
                     },
                 // This case should only trigger when all children died.
@@ -250,7 +242,7 @@ pub fn sv_loop(
                 // We can't trust simply calling `Pid::this()` in the child process to give the right
                 // PID for us, so we get it this way.
                 curr_pid = wait_for_signal(None, signal::SIGSTOP, InitialCont::No).unwrap();
-
+                // Continue until next syscall.
                 ptrace::syscall(curr_pid, None).unwrap();
             }
             // Child wants to end tracing.
@@ -289,8 +281,7 @@ pub fn sv_loop(
                         }
                     }
                 },
-            // Child entered a syscall; we wait for exits inside of this, so it
-            // should never trigger on return from a syscall we care about.
+            // Child entered or exited a syscall. For now we ignore this and just continue.
             ExecEvent::Syscall(pid) => {
                 ptrace::syscall(pid, None).unwrap();
             }
@@ -344,8 +335,8 @@ fn wait_for_signal(
                 return Err(ExecEnd(Some(code)));
             }
             wait::WaitStatus::Signaled(_, _, _) => return Err(ExecEnd(None)),
-            wait::WaitStatus::Stopped(pid, signal) => (signal, pid),
-            wait::WaitStatus::PtraceEvent(pid, signal, _) => (signal, pid),
+            wait::WaitStatus::Stopped(pid, signal)
+            | wait::WaitStatus::PtraceEvent(pid, signal, _) => (signal, pid),
             // This covers PtraceSyscall and variants that are impossible with
             // the flags set (e.g. WaitStatus::StillAlive).
             _ => {
@@ -486,7 +477,27 @@ fn handle_segfault(
     let stack_ptr = ch_stack.strict_add(CALLBACK_STACK_SIZE / 2);
     let regs_bak = ptrace::getregs(pid).unwrap();
     let mut new_regs = regs_bak;
-    let ip_prestep = regs_bak.ip();
+
+    // Read at least one instruction from the ip. It's possible that the instruction
+    // that triggered the segfault was short and at the end of the mapped text area,
+    // so some of these reads may fail; in that case, just write empty bytes. If all
+    // reads failed, the disassembler will report an error.
+    let instr = (0..(ARCH_MAX_INSTR_SIZE.div_ceil(ARCH_WORD_SIZE)))
+        .flat_map(|ofs| {
+            // This reads one word of memory; we divided by `ARCH_WORD_SIZE` above to compensate for that.
+            ptrace::read(
+                pid,
+                std::ptr::without_provenance_mut(
+                    regs_bak.ip().strict_add(ARCH_WORD_SIZE.strict_mul(ofs)),
+                ),
+            )
+            .unwrap_or_default()
+            .to_ne_bytes()
+        })
+        .collect::<Vec<_>>();
+
+    // Now figure out the size + type of access and log it down.
+    capstone_disassemble(&instr, addr, cs, acc_events).expect("Failed to disassemble instruction");
 
     // Move the instr ptr into the deprotection code.
     #[expect(clippy::as_conversions)]
@@ -526,33 +537,8 @@ fn handle_segfault(
         ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap();
     }
 
-    // Save registers and grab the bytes that were executed. This would
-    // be really nasty if it was a jump or similar but those thankfully
-    // won't do memory accesses and so can't trigger this!
     let regs_bak = ptrace::getregs(pid).unwrap();
     new_regs = regs_bak;
-    let ip_poststep = regs_bak.ip();
-
-    // Ensure that we've actually gone forwards.
-    assert!(ip_poststep > ip_prestep);
-    // But not by too much. 64 bytes should be "big enough" on ~any architecture.
-    assert!(ip_prestep.strict_add(64) > ip_poststep);
-
-    // We need to do reads/writes in word-sized chunks.
-    let diff = (ip_poststep.strict_sub(ip_prestep)).div_ceil(ARCH_WORD_SIZE);
-    let instr = (ip_prestep..ip_prestep.strict_add(diff)).fold(vec![], |mut ret, ip| {
-        // This only needs to be a valid pointer in the child process, not ours.
-        ret.append(
-            &mut ptrace::read(pid, std::ptr::without_provenance_mut(ip))
-                .unwrap()
-                .to_ne_bytes()
-                .to_vec(),
-        );
-        ret
-    });
-
-    // Now figure out the size + type of access and log it down.
-    capstone_disassemble(&instr, addr, cs, acc_events).expect("Failed to disassemble instruction");
 
     // Reprotect everything and continue.
     #[expect(clippy::as_conversions)]
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index e226a55d8b1..95e26ef5d5d 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -264,14 +264,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
 
+        // Handle the zero-sized case. The man page says:
+        // > If count is zero, read() may detect the errors described below.  In the absence of any
+        // > errors, or if read() does not check for errors, a read() with a count of 0 returns zero
+        // > and has no other effects.
+        if count == 0 {
+            this.write_null(dest)?;
+            return interp_ok(());
+        }
         // Non-deterministically decide to further reduce the count, simulating a partial read (but
-        // never to 0, that has different behavior).
-        let count =
-            if fd.nondet_short_accesses() && count >= 2 && this.machine.rng.get_mut().random() {
-                count / 2
-            } else {
-                count
-            };
+        // never to 0, that would indicate EOF).
+        let count = if this.machine.short_fd_operations
+            && fd.short_fd_operations()
+            && count >= 2
+            && this.machine.rng.get_mut().random()
+        {
+            count / 2 // since `count` is at least 2, the result is still at least 1
+        } else {
+            count
+        };
 
         trace!("read: FD mapped to {fd:?}");
         // We want to read at most `count` bytes. We are sure that `count` is not negative
@@ -338,14 +349,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
 
-        // Non-deterministically decide to further reduce the count, simulating a partial write (but
-        // never to 0, that has different behavior).
-        let count =
-            if fd.nondet_short_accesses() && count >= 2 && this.machine.rng.get_mut().random() {
-                count / 2
-            } else {
-                count
-            };
+        // Handle the zero-sized case. The man page says:
+        // > If count is zero and fd refers to a regular file, then write() may return a failure
+        // > status if one of the errors below is detected.  If no errors are detected, or error
+        // > detection is not performed, 0 is returned without causing any other effect.   If  count
+        // > is  zero  and  fd refers to a file other than a regular file, the results are not
+        // > specified.
+        if count == 0 {
+            // For now let's not open the can of worms of what exactly "not specified" could mean...
+            this.write_null(dest)?;
+            return interp_ok(());
+        }
+        // Non-deterministically decide to further reduce the count, simulating a partial write.
+        // We avoid reducing the write size to 0: the docs seem to be entirely fine with that,
+        // but the standard library is not (https://github.com/rust-lang/rust/issues/145959).
+        let count = if this.machine.short_fd_operations
+            && fd.short_fd_operations()
+            && count >= 2
+            && this.machine.rng.get_mut().random()
+        {
+            count / 2
+        } else {
+            count
+        };
 
         let finish = {
             let dest = dest.clone();
diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
index 2d35ef064db..ee7deb8d383 100644
--- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
@@ -37,11 +37,6 @@ impl FileDescription for EventFd {
         "event"
     }
 
-    fn nondet_short_accesses(&self) -> bool {
-        // We always read and write exactly one `u64`.
-        false
-    }
-
     fn close<'tcx>(
         self,
         _communicate_allowed: bool,
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index 817ddd7954d..7eb82851033 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -123,6 +123,14 @@ impl FileDescription for AnonSocket {
         anonsocket_write(self, ptr, len, ecx, finish)
     }
 
+    fn short_fd_operations(&self) -> bool {
+        // Pipes guarantee that sufficiently small accesses are not broken apart:
+        // <https://pubs.opengroup.org/onlinepubs/9799919799/functions/write.html#tag_17_699_08>.
+        // For now, we don't bother checking for the size, and just entirely disable
+        // short accesses on pipes.
+        matches!(self.fd_type, AnonSocketType::Socketpair)
+    }
+
     fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         self
     }
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index 8a965ea316d..92d6321bed1 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -289,9 +289,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
 
         if this.ptr_is_null(target_handle_ptr)? {
-            throw_unsup_format!(
-                "`DuplicateHandle` `lpTargetHandle` parameter is null, which is unsupported"
-            );
+            throw_machine_stop!(TerminationInfo::Abort(
+                "`DuplicateHandle` `lpTargetHandle` parameter must not be null, as otherwise the \
+                newly created handle is leaked"
+                    .to_string()
+            ));
         }
 
         if options != this.eval_windows("c", "DUPLICATE_SAME_ACCESS") {
diff --git a/src/tools/miri/tests/deps/Cargo.lock b/src/tools/miri/tests/deps/Cargo.lock
index 4b783ebdc4e..65ca4215c60 100644
--- a/src/tools/miri/tests/deps/Cargo.lock
+++ b/src/tools/miri/tests/deps/Cargo.lock
@@ -296,9 +296,9 @@ dependencies = [
 
 [[package]]
 name = "slab"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
 
 [[package]]
 name = "socket2"
diff --git a/src/tools/miri/tests/fail/intrinsics/funnel_shl.rs b/src/tools/miri/tests/fail/intrinsics/funnel_shl.rs
new file mode 100644
index 00000000000..40b61f65ebe
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/funnel_shl.rs
@@ -0,0 +1,7 @@
+#![feature(core_intrinsics, funnel_shifts)]
+
+fn main() {
+    unsafe {
+        std::intrinsics::unchecked_funnel_shl(1_u32, 2, 32); //~ ERROR: Undefined Behavior
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/funnel_shl.stderr b/src/tools/miri/tests/fail/intrinsics/funnel_shl.stderr
new file mode 100644
index 00000000000..fc828021b13
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/funnel_shl.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `assume` called with `false`
+  --> tests/fail/intrinsics/funnel_shl.rs:LL:CC
+   |
+LL |         std::intrinsics::unchecked_funnel_shl(1_u32, 2, 32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/funnel_shl.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/funnel_shr.rs b/src/tools/miri/tests/fail/intrinsics/funnel_shr.rs
new file mode 100644
index 00000000000..95822656397
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/funnel_shr.rs
@@ -0,0 +1,7 @@
+#![feature(core_intrinsics, funnel_shifts)]
+
+fn main() {
+    unsafe {
+        std::intrinsics::unchecked_funnel_shr(1_u32, 2, 32); //~ ERROR: Undefined Behavior
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/funnel_shr.stderr b/src/tools/miri/tests/fail/intrinsics/funnel_shr.stderr
new file mode 100644
index 00000000000..7361df1b4c7
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/funnel_shr.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `assume` called with `false`
+  --> tests/fail/intrinsics/funnel_shr.rs:LL:CC
+   |
+LL |         std::intrinsics::unchecked_funnel_shr(1_u32, 2, 32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/funnel_shr.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/frozen-lazy-write-to-surrounding.rs b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs
new file mode 100644
index 00000000000..7d51050f32b
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs
@@ -0,0 +1,9 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+fn main() {
+    // Since the "inside" part is `!Freeze`, the permission to mutate is gone.
+    let pair = ((), 1);
+    let x = &pair.0;
+    let ptr = (&raw const *x).cast::<i32>().cast_mut();
+    unsafe { ptr.write(0) }; //~ERROR: /write access .* forbidden/
+}
diff --git a/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.stderr b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.stderr
new file mode 100644
index 00000000000..e9800468c57
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.stderr
@@ -0,0 +1,21 @@
+error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
+  --> tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs:LL:CC
+   |
+LL |     unsafe { ptr.write(0) };
+   |              ^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
+   = help: the accessed tag <TAG> has state Frozen which forbids this child write access
+help: the accessed tag <TAG> was created here, in the initial state Frozen
+  --> tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs:LL:CC
+   |
+LL |     let x = &pair.0;
+   |             ^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.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/native-lib/aggregate_arguments.c b/src/tools/miri/tests/native-lib/aggregate_arguments.c
new file mode 100644
index 00000000000..8ad687f2aec
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/aggregate_arguments.c
@@ -0,0 +1,52 @@
+#include <stdint.h>
+
+// See comments in build_native_lib()
+#define EXPORT __attribute__((visibility("default")))
+
+/* Test: fail/pass_struct_expose_only_range */
+
+typedef struct HasPointer {
+  uint8_t *ptr;
+} HasPointer;
+
+EXPORT uint8_t access_struct_ptr(const HasPointer s) {
+  return *s.ptr;
+}
+
+/* Test: test_pass_struct */
+
+typedef struct PassMe {
+    int32_t value;
+    int64_t other_value;
+} PassMe;
+
+EXPORT int64_t pass_struct(const PassMe pass_me) {
+  return pass_me.value + pass_me.other_value;
+}
+
+/* Test: test_pass_struct_complex */
+
+typedef struct Part1 {
+    uint16_t high;
+    uint16_t low;
+} Part1;
+
+typedef struct Part2 {
+    uint32_t bits;
+} Part2;
+
+typedef struct ComplexStruct {
+    Part1 part_1;
+    Part2 part_2;
+    uint32_t part_3;
+} ComplexStruct;
+
+EXPORT int32_t pass_struct_complex(const ComplexStruct complex, uint16_t high, uint16_t low, uint32_t bits) {
+  if (complex.part_1.high == high && complex.part_1.low == low
+      && complex.part_2.bits == bits
+      && complex.part_3 == bits)
+    return 0;
+  else {
+    return 1;
+  }
+}
diff --git a/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.rs b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.rs
new file mode 100644
index 00000000000..a2b43031a29
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.rs
@@ -0,0 +1,23 @@
+//@compile-flags: -Zmiri-permissive-provenance
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct HasPointer {
+    ptr: *const u8,
+}
+
+extern "C" {
+    fn access_struct_ptr(s: HasPointer) -> u8;
+}
+
+fn main() {
+    let structs = vec![HasPointer { ptr: &0 }, HasPointer { ptr: &1 }];
+    unsafe {
+        let r = access_struct_ptr(structs[1]);
+        assert_eq!(r, 1);
+        // There are two pointers stored in the allocation backing `structs`; ensure
+        // we only exposed the one that was actually passed to C.
+        let _val = *std::ptr::with_exposed_provenance::<u8>(structs[1].ptr.addr()); // fine, ptr got sent to C
+        let _val = *std::ptr::with_exposed_provenance::<u8>(structs[0].ptr.addr()); //~ ERROR: memory access failed
+    };
+}
diff --git a/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.stderr b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.stderr
new file mode 100644
index 00000000000..a8f85001c23
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.stderr
@@ -0,0 +1,28 @@
+warning: sharing memory with a native function called via FFI
+  --> tests/native-lib/fail/pass_struct_expose_only_range.rs:LL:CC
+   |
+LL |         let r = access_struct_ptr(structs[1]);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function
+   |
+   = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory
+   = help: in particular, Miri assumes that the native call initializes all memory it has access to
+   = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory
+   = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free
+   = note: BACKTRACE:
+   = note: inside `main` at tests/native-lib/fail/pass_struct_expose_only_range.rs:LL:CC
+
+error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+  --> tests/native-lib/fail/pass_struct_expose_only_range.rs:LL:CC
+   |
+LL |         let _val = *std::ptr::with_exposed_provenance::<u8>(structs[0].ptr.addr());
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/native-lib/fail/pass_struct_expose_only_range.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; 1 warning emitted
+
diff --git a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs
new file mode 100644
index 00000000000..cf8315e0fd9
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs
@@ -0,0 +1,19 @@
+// Only works on Unix targets
+//@ignore-target: windows wasm
+//@only-on-host
+
+#![allow(improper_ctypes)]
+
+pub struct PassMe {
+    pub value: i32,
+    pub other_value: i64,
+}
+
+extern "C" {
+    fn pass_struct(s: PassMe) -> i64;
+}
+
+fn main() {
+    let pass_me = PassMe { value: 42, other_value: 1337 };
+    unsafe { pass_struct(pass_me) }; //~ ERROR: unsupported operation: passing a non-#[repr(C)] struct over FFI
+}
diff --git a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr
new file mode 100644
index 00000000000..90e59a31da4
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr
@@ -0,0 +1,14 @@
+error: unsupported operation: passing a non-#[repr(C)] struct over FFI: PassMe
+  --> tests/native-lib/fail/struct_not_extern_c.rs:LL:CC
+   |
+LL |     unsafe { pass_struct(pass_me) };
+   |              ^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here
+   |
+   = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
+   = note: BACKTRACE:
+   = note: inside `main` at tests/native-lib/fail/struct_not_extern_c.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/native-lib/fail/uninit_struct.rs b/src/tools/miri/tests/native-lib/fail/uninit_struct.rs
new file mode 100644
index 00000000000..cf61c7f3915
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/fail/uninit_struct.rs
@@ -0,0 +1,27 @@
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct ComplexStruct {
+    part_1: Part1,
+    part_2: Part2,
+    part_3: u32,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct Part1 {
+    high: u16,
+    low: u16,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct Part2 {
+    bits: u32,
+}
+
+extern "C" {
+    fn pass_struct_complex(s: ComplexStruct, high: u16, low: u16, bits: u32) -> i32;
+}
+
+fn main() {
+    let arg = std::mem::MaybeUninit::<ComplexStruct>::uninit();
+    unsafe { pass_struct_complex(*arg.as_ptr(), 0, 0, 0) }; //~ ERROR: Undefined Behavior: constructing invalid value
+}
diff --git a/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr b/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr
new file mode 100644
index 00000000000..0fe6ad9c77b
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value at .part_1.high: encountered uninitialized memory, but expected an integer
+  --> tests/native-lib/fail/uninit_struct.rs:LL:CC
+   |
+LL |     unsafe { pass_struct_complex(*arg.as_ptr(), 0, 0, 0) };
+   |                                  ^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/native-lib/fail/uninit_struct.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/native-lib/pass/aggregate_arguments.rs b/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs
new file mode 100644
index 00000000000..55acb240612
--- /dev/null
+++ b/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs
@@ -0,0 +1,52 @@
+fn main() {
+    test_pass_struct();
+    test_pass_struct_complex();
+}
+
+/// Test passing a basic struct as an argument.
+fn test_pass_struct() {
+    // Exactly two fields, so that we hit the ScalarPair case.
+    #[repr(C)]
+    struct PassMe {
+        value: i32,
+        other_value: i64,
+    }
+
+    extern "C" {
+        fn pass_struct(s: PassMe) -> i64;
+    }
+
+    let pass_me = PassMe { value: 42, other_value: 1337 };
+    assert_eq!(unsafe { pass_struct(pass_me) }, 42 + 1337);
+}
+
+/// Test passing a more complex struct as an argument.
+fn test_pass_struct_complex() {
+    #[repr(C)]
+    struct ComplexStruct {
+        part_1: Part1,
+        part_2: Part2,
+        part_3: u32,
+    }
+    #[repr(C)]
+    struct Part1 {
+        high: u16,
+        low: u16,
+    }
+    #[repr(C)]
+    struct Part2 {
+        bits: u32,
+    }
+
+    extern "C" {
+        fn pass_struct_complex(s: ComplexStruct, high: u16, low: u16, bits: u32) -> i32;
+    }
+
+    let high = 0xabcd;
+    let low = 0xef01;
+    let bits = 0xabcdef01;
+
+    let complex =
+        ComplexStruct { part_1: Part1 { high, low }, part_2: Part2 { bits }, part_3: bits };
+    assert_eq!(unsafe { pass_struct_complex(complex, high, low, bits) }, 0);
+}
diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
index 4f3c37f00c1..bab73f7cf17 100644
--- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
+++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
@@ -1,6 +1,7 @@
 //@revisions: trace notrace
 //@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu
 //@[trace] compile-flags: -Zmiri-native-lib-enable-tracing
+//@compile-flags: -Zmiri-permissive-provenance
 
 fn main() {
     test_access_pointer();
diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
index 4ca19046b67..7b756603d92 100644
--- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
@@ -2,20 +2,20 @@
 //@compile-flags: -Zmiri-disable-isolation
 #![allow(nonstandard_style)]
 
-use std::io::{ErrorKind, Read, Write};
+use std::io::{ErrorKind, Read, Seek, SeekFrom, Write};
 use std::os::windows::ffi::OsStrExt;
-use std::os::windows::io::AsRawHandle;
+use std::os::windows::io::{AsRawHandle, FromRawHandle};
 use std::path::Path;
-use std::{fs, ptr};
+use std::{fs, mem, ptr};
 
 #[path = "../../utils/mod.rs"]
 mod utils;
 
 use windows_sys::Wdk::Storage::FileSystem::{NtReadFile, NtWriteFile};
 use windows_sys::Win32::Foundation::{
-    CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ,
-    GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED,
-    STATUS_IO_DEVICE_ERROR, STATUS_SUCCESS, SetLastError,
+    CloseHandle, DUPLICATE_SAME_ACCESS, DuplicateHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS,
+    ERROR_IO_DEVICE, FALSE, GENERIC_READ, GENERIC_WRITE, GetLastError, RtlNtStatusToDosError,
+    STATUS_ACCESS_DENIED, STATUS_IO_DEVICE_ERROR, STATUS_SUCCESS, SetLastError,
 };
 use windows_sys::Win32::Storage::FileSystem::{
     BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW,
@@ -24,6 +24,7 @@ use windows_sys::Win32::Storage::FileSystem::{
     FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFilePointerEx,
 };
 use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
+use windows_sys::Win32::System::Threading::GetCurrentProcess;
 
 fn main() {
     unsafe {
@@ -36,6 +37,7 @@ fn main() {
         test_ntstatus_to_dos();
         test_file_read_write();
         test_file_seek();
+        test_dup_handle();
     }
 }
 
@@ -273,6 +275,39 @@ unsafe fn test_file_read_write() {
     assert_eq!(GetLastError(), 1234);
 }
 
+unsafe fn test_dup_handle() {
+    let temp = utils::tmp().join("test_dup.txt");
+
+    let mut file1 = fs::File::options().read(true).write(true).create(true).open(&temp).unwrap();
+
+    file1.write_all(b"Hello, World!\n").unwrap();
+    file1.seek(SeekFrom::Start(0)).unwrap();
+
+    let first_handle = file1.as_raw_handle();
+
+    let cur_proc = GetCurrentProcess();
+    let mut second_handle = mem::zeroed();
+    let res = DuplicateHandle(
+        cur_proc,
+        first_handle,
+        cur_proc,
+        &mut second_handle,
+        0,
+        FALSE,
+        DUPLICATE_SAME_ACCESS,
+    );
+    assert!(res != 0);
+
+    let mut buf1 = [0; 5];
+    file1.read(&mut buf1).unwrap();
+    assert_eq!(&buf1, b"Hello");
+
+    let mut file2 = fs::File::from_raw_handle(second_handle);
+    let mut buf2 = [0; 5];
+    file2.read(&mut buf2).unwrap();
+    assert_eq!(&buf2, b", Wor");
+}
+
 unsafe fn test_file_seek() {
     let temp = utils::tmp().join("test_file_seek.txt");
     let mut file = fs::File::options().create(true).write(true).read(true).open(&temp).unwrap();
diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
index 6a625e597df..82976326a8d 100644
--- a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
+++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
@@ -23,7 +23,8 @@ fn main() {
     not_unpin_not_protected();
     write_does_not_invalidate_all_aliases();
     box_into_raw_allows_interior_mutable_alias();
-    cell_inside_struct()
+    cell_inside_struct();
+    zst();
 }
 
 // Make sure that reading from an `&mut` does, like reborrowing to `&`,
@@ -287,3 +288,22 @@ fn cell_inside_struct() {
     // Writing to `field1`, which is reserved, should also be allowed.
     (*a).field1 = 88;
 }
+
+/// ZST reborrows on various kinds of dangling pointers are valid.
+fn zst() {
+    unsafe {
+        // Integer pointer.
+        let ptr = ptr::without_provenance_mut::<()>(15);
+        let _ref = &mut *ptr;
+
+        // Out-of-bounds pointer.
+        let mut b = Box::new(0u8);
+        let ptr = (&raw mut *b).wrapping_add(15) as *mut ();
+        let _ref = &mut *ptr;
+
+        // Deallocated pointer.
+        let ptr = &raw mut *b as *mut ();
+        drop(b);
+        let _ref = &mut *ptr;
+    }
+}
diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs
index a92359758da..142ac9cc8ca 100644
--- a/src/tools/miri/tests/pass/concurrency/sync.rs
+++ b/src/tools/miri/tests/pass/concurrency/sync.rs
@@ -9,7 +9,8 @@ use std::time::{Duration, Instant};
 
 // We are expecting to sleep for 10ms. How long of a sleep we are accepting?
 // Even with 1000ms we still see this test fail on macOS runners.
-const MAX_SLEEP_TIME_MS: u64 = 2000;
+// On a aarch64-pc-windows-msvc runner, we saw 2.7s!
+const MAX_SLEEP_TIME_MS: u64 = 4000;
 
 // Check if Rust barriers are working.
 
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index fe7316c6680..9f1b3f612b2 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -39,9 +39,8 @@ macro_rules! assert_approx_eq {
     }};
 
     ($a:expr, $b: expr) => {
-        // accept up to 12ULP (4ULP for host floats and 4ULP for miri artificial error and 4 for any additional effects
-        // due to having multiple error sources.
-        assert_approx_eq!($a, $b, 12);
+        // accept up to 8ULP (4ULP for host floats and 4ULP for miri artificial error).
+        assert_approx_eq!($a, $b, 8);
     };
 }
 
@@ -176,6 +175,7 @@ fn assert_eq_msg<T: PartialEq + Debug>(x: T, y: T, msg: impl Display) {
 }
 
 /// Check that floats have bitwise equality
+#[track_caller]
 fn assert_biteq<F: Float>(a: F, b: F, msg: impl Display) {
     let ab = a.to_bits();
     let bb = b.to_bits();
@@ -189,6 +189,7 @@ fn assert_biteq<F: Float>(a: F, b: F, msg: impl Display) {
 }
 
 /// Check that two floats have equality
+#[track_caller]
 fn assert_feq<F: Float>(a: F, b: F, msg: impl Display) {
     let ab = a.to_bits();
     let bb = b.to_bits();
@@ -1051,6 +1052,10 @@ pub fn libm() {
     assert_eq!(42f64.powf(0.0), 1.0);
     assert_eq!(f32::INFINITY.powf(0.0), 1.0);
     assert_eq!(f64::INFINITY.powf(0.0), 1.0);
+    assert_eq!(f32::NEG_INFINITY.powi(3), f32::NEG_INFINITY);
+    assert_eq!(f32::NEG_INFINITY.powi(2), f32::INFINITY);
+    assert_eq!(f64::INFINITY.powi(3), f64::INFINITY);
+    assert_eq!(f64::INFINITY.powi(2), f64::INFINITY);
 
     // f*::NAN is a quiet NAN and should return 1 as well.
     assert_eq!(f32::NAN.powi(0), 1.0);
@@ -1088,6 +1093,8 @@ pub fn libm() {
 
     assert_approx_eq!(1f32.exp_m1(), f32::consts::E - 1.0);
     assert_approx_eq!(1f64.exp_m1(), f64::consts::E - 1.0);
+    assert_approx_eq!(f32::NEG_INFINITY.exp_m1(), -1.0);
+    assert_approx_eq!(f64::NEG_INFINITY.exp_m1(), -1.0);
 
     assert_approx_eq!(10f32.exp2(), 1024f32);
     assert_approx_eq!(50f64.exp2(), 1125899906842624f64);
@@ -1123,6 +1130,7 @@ pub fn libm() {
     assert_eq!(ldexp(0.65f64, 3i32), 5.2f64);
     assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY);
     assert_eq!(ldexp(1.42, -0xFFFF), 0f64);
+    assert_eq!(ldexp(42.0, 0), 42.0);
 
     // Trigonometric functions.
 
@@ -1131,8 +1139,13 @@ pub fn libm() {
     assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64);
     assert_approx_eq!(f32::consts::FRAC_PI_6.sin(), 0.5);
     assert_approx_eq!(f64::consts::FRAC_PI_6.sin(), 0.5);
-    assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4);
-    assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4);
+    // Increase error tolerance to 16ULP because of the extra operation.
+    assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4, 16);
+    assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4, 16);
+    assert_biteq(0.0f32.asin(), 0.0f32, "asin(+0) = +0");
+    assert_biteq((-0.0f32).asin(), -0.0, "asin(-0) = -0");
+    assert_biteq(0.0f64.asin(), 0.0, "asin(+0) = +0");
+    assert_biteq((-0.0f64).asin(), -0.0, "asin(-0) = -0");
 
     assert_approx_eq!(1.0f32.sinh(), 1.1752012f32);
     assert_approx_eq!(1.0f64.sinh(), 1.1752011936438014f64);
@@ -1159,11 +1172,18 @@ pub fn libm() {
     assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64);
     assert_approx_eq!(f32::consts::FRAC_PI_3.cos(), 0.5);
     assert_approx_eq!(f64::consts::FRAC_PI_3.cos(), 0.5);
-    assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4);
-    assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4);
+    // Increase error tolerance to 16ULP because of the extra operation.
+    assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4, 16);
+    assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4, 16);
+    assert_biteq(1.0f32.acos(), 0.0, "acos(1) = 0");
+    assert_biteq(1.0f64.acos(), 0.0, "acos(1) = 0");
 
-    assert_approx_eq!(1.0f32.cosh(), 1.54308f32);
+    assert_approx_eq!(1.0f32.cosh(), 1.5430806f32);
     assert_approx_eq!(1.0f64.cosh(), 1.5430806348152437f64);
+    assert_eq!(0.0f32.cosh(), 1.0);
+    assert_eq!(0.0f64.cosh(), 1.0);
+    assert_eq!((-0.0f32).cosh(), 1.0);
+    assert_eq!((-0.0f64).cosh(), 1.0);
     assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
     assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
 
@@ -1173,6 +1193,47 @@ pub fn libm() {
     assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan());
     assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32);
     assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32);
+    // C standard defines a bunch of fixed outputs for atan2
+    macro_rules! fixed_atan2_cases{
+        ($float_type:ident) => {{
+            use std::$float_type::consts::{PI, FRAC_PI_2, FRAC_PI_4};
+            use $float_type::{INFINITY, NEG_INFINITY};
+
+            // atan2(±0,−0) = ±π.
+            assert_eq!($float_type::atan2(0.0, -0.0), PI, "atan2(0,−0) = π");
+            assert_eq!($float_type::atan2(-0.0, -0.0), -PI, "atan2(-0,−0) = -π");
+
+            // atan2(±0, y) = ±π for y < 0.
+            assert_eq!($float_type::atan2(0.0, -1.0), PI, "atan2(0, y) = π for y < 0.");
+            assert_eq!($float_type::atan2(-0.0, -1.0), -PI, "atan2(-0, y) = -π for y < 0.");
+
+            // atan2(x, ±0) = −π/2 for x < 0.
+            assert_eq!($float_type::atan2(-1.0, 0.0), -FRAC_PI_2, "atan2(x, 0) = −π/2 for x < 0");
+            assert_eq!($float_type::atan2(-1.0, -0.0), -FRAC_PI_2, "atan2(x, -0) = −π/2 for x < 0");
+
+            // atan2(x, ±0) =  π/2 for x > 0.
+            assert_eq!($float_type::atan2(1.0, 0.0), FRAC_PI_2, "atan2(x, 0) =  π/2 for x > 0.");
+            assert_eq!($float_type::atan2(1.0, -0.0), FRAC_PI_2, "atan2(x, -0) =  π/2 for x > 0.");
+
+            // atan2(±x,−∞) = ±π for finite x > 0.
+            assert_eq!($float_type::atan2(1.0, NEG_INFINITY), PI, "atan2(x, −∞) = π for finite x > 0");
+            assert_eq!($float_type::atan2(-1.0, NEG_INFINITY), -PI, "atan2(-x, −∞) = -π for finite x > 0");
+
+            // atan2(±∞, y) returns ±π/2 for finite y.
+            assert_eq!($float_type::atan2(INFINITY, 1.0), FRAC_PI_2, "atan2(+∞, y) returns π/2 for finite y");
+            assert_eq!($float_type::atan2(NEG_INFINITY, 1.0), -FRAC_PI_2, "atan2(-∞, y) returns -π/2 for finite y");
+
+            // atan2(±∞, −∞) = ±3π/4
+            assert_eq!($float_type::atan2(INFINITY, NEG_INFINITY), 3.0 * FRAC_PI_4, "atan2(+∞, −∞) = 3π/4");
+            assert_eq!($float_type::atan2(NEG_INFINITY, NEG_INFINITY), -3.0 * FRAC_PI_4, "atan2(-∞, −∞) = -3π/4");
+
+            // atan2(±∞, +∞) = ±π/4
+            assert_eq!($float_type::atan2(INFINITY, INFINITY), FRAC_PI_4, "atan2(+∞, +∞) = π/4");
+            assert_eq!($float_type::atan2(NEG_INFINITY, INFINITY), -FRAC_PI_4, "atan2(-∞, +∞) = -π/4");
+        }}
+    }
+    fixed_atan2_cases!(f32);
+    fixed_atan2_cases!(f64);
 
     assert_approx_eq!(
         1.0f32.tanh(),
@@ -1182,6 +1243,11 @@ pub fn libm() {
         1.0f64.tanh(),
         (1.0 - f64::consts::E.powi(-2)) / (1.0 + f64::consts::E.powi(-2))
     );
+    assert_eq!(f32::INFINITY.tanh(), 1.0);
+    assert_eq!(f32::NEG_INFINITY.tanh(), -1.0);
+    assert_eq!(f64::INFINITY.tanh(), 1.0);
+    assert_eq!(f64::NEG_INFINITY.tanh(), -1.0);
+
     assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
     assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
 
@@ -1202,8 +1268,14 @@ pub fn libm() {
 
     assert_approx_eq!(1.0f32.erf(), 0.84270079294971486934122063508260926f32);
     assert_approx_eq!(1.0f64.erf(), 0.84270079294971486934122063508260926f64);
+    assert_eq!(f32::INFINITY.erf(), 1.0);
+    assert_eq!(f64::INFINITY.erf(), 1.0);
     assert_approx_eq!(1.0f32.erfc(), 0.15729920705028513065877936491739074f32);
     assert_approx_eq!(1.0f64.erfc(), 0.15729920705028513065877936491739074f64);
+    assert_eq!(f32::NEG_INFINITY.erfc(), 2.0);
+    assert_eq!(f64::NEG_INFINITY.erfc(), 2.0);
+    assert_eq!(f32::INFINITY.erfc(), 0.0);
+    assert_eq!(f64::INFINITY.erfc(), 0.0);
 }
 
 fn test_fast() {
@@ -1413,7 +1485,6 @@ fn test_non_determinism() {
     }
     pub fn test_operations_f32(a: f32, b: f32) {
         test_operations_f!(a, b);
-        // FIXME: some are temporarily disabled as it breaks std tests.
         ensure_nondet(|| a.powf(b));
         ensure_nondet(|| a.powi(2));
         ensure_nondet(|| a.log(b));
@@ -1422,35 +1493,34 @@ fn test_non_determinism() {
         ensure_nondet(|| f32::consts::E.ln());
         ensure_nondet(|| 10f32.log10());
         ensure_nondet(|| 8f32.log2());
-        // ensure_nondet(|| 1f32.ln_1p());
-        // ensure_nondet(|| 27.0f32.cbrt());
-        // ensure_nondet(|| 3.0f32.hypot(4.0f32));
+        ensure_nondet(|| 1f32.ln_1p());
+        ensure_nondet(|| 27.0f32.cbrt());
+        ensure_nondet(|| 3.0f32.hypot(4.0f32));
         ensure_nondet(|| 1f32.sin());
         ensure_nondet(|| 1f32.cos());
         // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version,
         // which means the little rounding errors Miri introduces are discarded by the cast down to
         // `f32`. Just skip the test for them.
-        // if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) {
-        //     ensure_nondet(|| 1.0f32.tan());
-        //     ensure_nondet(|| 1.0f32.asin());
-        //     ensure_nondet(|| 5.0f32.acos());
-        //     ensure_nondet(|| 1.0f32.atan());
-        //     ensure_nondet(|| 1.0f32.atan2(2.0f32));
-        //     ensure_nondet(|| 1.0f32.sinh());
-        //     ensure_nondet(|| 1.0f32.cosh());
-        //     ensure_nondet(|| 1.0f32.tanh());
-        // }
-        // ensure_nondet(|| 1.0f32.asinh());
-        // ensure_nondet(|| 2.0f32.acosh());
-        // ensure_nondet(|| 0.5f32.atanh());
-        // ensure_nondet(|| 5.0f32.gamma());
-        // ensure_nondet(|| 5.0f32.ln_gamma());
-        // ensure_nondet(|| 5.0f32.erf());
-        // ensure_nondet(|| 5.0f32.erfc());
+        if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) {
+            ensure_nondet(|| 1.0f32.tan());
+            ensure_nondet(|| 1.0f32.asin());
+            ensure_nondet(|| 5.0f32.acos());
+            ensure_nondet(|| 1.0f32.atan());
+            ensure_nondet(|| 1.0f32.atan2(2.0f32));
+            ensure_nondet(|| 1.0f32.sinh());
+            ensure_nondet(|| 1.0f32.cosh());
+            ensure_nondet(|| 1.0f32.tanh());
+        }
+        ensure_nondet(|| 1.0f32.asinh());
+        ensure_nondet(|| 2.0f32.acosh());
+        ensure_nondet(|| 0.5f32.atanh());
+        ensure_nondet(|| 5.0f32.gamma());
+        ensure_nondet(|| 5.0f32.ln_gamma());
+        ensure_nondet(|| 5.0f32.erf());
+        ensure_nondet(|| 5.0f32.erfc());
     }
     pub fn test_operations_f64(a: f64, b: f64) {
         test_operations_f!(a, b);
-        // FIXME: some are temporarily disabled as it breaks std tests.
         ensure_nondet(|| a.powf(b));
         ensure_nondet(|| a.powi(2));
         ensure_nondet(|| a.log(b));
@@ -1459,26 +1529,26 @@ fn test_non_determinism() {
         ensure_nondet(|| 3f64.ln());
         ensure_nondet(|| f64::consts::E.log10());
         ensure_nondet(|| f64::consts::E.log2());
-        // ensure_nondet(|| 1f64.ln_1p());
-        // ensure_nondet(|| 27.0f64.cbrt());
-        // ensure_nondet(|| 3.0f64.hypot(4.0f64));
+        ensure_nondet(|| 1f64.ln_1p());
+        ensure_nondet(|| 27.0f64.cbrt());
+        ensure_nondet(|| 3.0f64.hypot(4.0f64));
         ensure_nondet(|| 1f64.sin());
         ensure_nondet(|| 1f64.cos());
-        // ensure_nondet(|| 1.0f64.tan());
-        // ensure_nondet(|| 1.0f64.asin());
-        // ensure_nondet(|| 5.0f64.acos());
-        // ensure_nondet(|| 1.0f64.atan());
-        // ensure_nondet(|| 1.0f64.atan2(2.0f64));
-        // ensure_nondet(|| 1.0f64.sinh());
-        // ensure_nondet(|| 1.0f64.cosh());
-        // ensure_nondet(|| 1.0f64.tanh());
-        // ensure_nondet(|| 1.0f64.asinh());
-        // ensure_nondet(|| 3.0f64.acosh());
-        // ensure_nondet(|| 0.5f64.atanh());
-        // ensure_nondet(|| 5.0f64.gamma());
-        // ensure_nondet(|| 5.0f64.ln_gamma());
-        // ensure_nondet(|| 5.0f64.erf());
-        // ensure_nondet(|| 5.0f64.erfc());
+        ensure_nondet(|| 1.0f64.tan());
+        ensure_nondet(|| 1.0f64.asin());
+        ensure_nondet(|| 5.0f64.acos());
+        ensure_nondet(|| 1.0f64.atan());
+        ensure_nondet(|| 1.0f64.atan2(2.0f64));
+        ensure_nondet(|| 1.0f64.sinh());
+        ensure_nondet(|| 1.0f64.cosh());
+        ensure_nondet(|| 1.0f64.tanh());
+        ensure_nondet(|| 1.0f64.asinh());
+        ensure_nondet(|| 3.0f64.acosh());
+        ensure_nondet(|| 0.5f64.atanh());
+        ensure_nondet(|| 5.0f64.gamma());
+        ensure_nondet(|| 5.0f64.ln_gamma());
+        ensure_nondet(|| 5.0f64.erf());
+        ensure_nondet(|| 5.0f64.erfc());
     }
     pub fn test_operations_f128(a: f128, b: f128) {
         test_operations_f!(a, b);
diff --git a/src/tools/miri/tests/pass/float_extra_rounding_error.rs b/src/tools/miri/tests/pass/float_extra_rounding_error.rs
new file mode 100644
index 00000000000..24d7cf2ccee
--- /dev/null
+++ b/src/tools/miri/tests/pass/float_extra_rounding_error.rs
@@ -0,0 +1,31 @@
+//! Check that the flags to control the extra rounding error work.
+//@revisions: random max none
+//@[max]compile-flags: -Zmiri-max-extra-rounding-error
+//@[none]compile-flags: -Zmiri-no-extra-rounding-error
+#![feature(cfg_select)]
+
+use std::collections::HashSet;
+use std::hint::black_box;
+
+fn main() {
+    let expected = cfg_select! {
+        random => 9, // -4 ..= +4 ULP error
+        max => 2,
+        none => 1,
+    };
+    // Call `sin(0.5)` a bunch of times and see how many different values we get.
+    let mut values = HashSet::new();
+    for _ in 0..(expected * 16) {
+        let val = black_box(0.5f64).sin();
+        values.insert(val.to_bits());
+    }
+    assert_eq!(values.len(), expected);
+
+    if !cfg!(none) {
+        // Ensure the smallest and biggest value are 8 ULP apart.
+        // We can just subtract the raw bit representations for this.
+        let min = *values.iter().min().unwrap();
+        let max = *values.iter().max().unwrap();
+        assert_eq!(min.abs_diff(max), 8);
+    }
+}
diff --git a/src/tools/miri/tests/pass/intrinsics/integer.rs b/src/tools/miri/tests/pass/intrinsics/integer.rs
index 13e7bd8e1b9..8727b6d3c87 100644
--- a/src/tools/miri/tests/pass/intrinsics/integer.rs
+++ b/src/tools/miri/tests/pass/intrinsics/integer.rs
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: MIT OR Apache-2.0
 // SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
 
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, funnel_shifts)]
 use std::intrinsics::*;
 
 pub fn main() {
@@ -143,5 +143,11 @@ pub fn main() {
 
         assert_eq!(unchecked_mul(6u8, 7), 42);
         assert_eq!(unchecked_mul(13, -5), -65);
+
+        assert_eq!(unchecked_funnel_shl(1_u32, 2, 5), 32);
+        assert_eq!(unchecked_funnel_shl(1_u32, 2, 31), 0x80000001);
+
+        assert_eq!(unchecked_funnel_shr(1_u32, 2, 5), 0x08000000);
+        assert_eq!(unchecked_funnel_shr(1_u32, 2, 31), 2);
     }
 }
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index e7f11c54704..022dcc5dcba 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -72,7 +72,9 @@ fn test_file() {
 
     // Writing to a file opened for reading should error (and not stop interpretation). std does not
     // categorize the error so we don't check for details.
-    file.write(&[]).unwrap_err();
+    file.write(&[0]).unwrap_err();
+    // However, writing 0 bytes can succeed or fail.
+    let _ignore = file.write(&[]);
 
     // Removing file should succeed.
     remove_file(&path).unwrap();
diff --git a/src/tools/miri/tests/pass/shims/x86/rounding-error.rs b/src/tools/miri/tests/pass/shims/x86/rounding-error.rs
new file mode 100644
index 00000000000..bf56111b2e4
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/x86/rounding-error.rs
@@ -0,0 +1,37 @@
+// We're testing x86 target specific features
+//@only-target: x86_64 i686
+
+//! rsqrt and rcp SSE/AVX operations are approximate. We use that as license to treat them as
+//! non-deterministic. Ensure that we do indeed see random results within the expected error bounds.
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+use std::collections::HashSet;
+
+fn main() {
+    let mut vals = HashSet::new();
+    for _ in 0..50 {
+        unsafe {
+            // Compute the inverse square root of 4.0, four times.
+            let a = _mm_setr_ps(4.0, 4.0, 4.0, 4.0);
+            let exact = 0.5;
+            let r = _mm_rsqrt_ps(a);
+            let r: [f32; 4] = std::mem::transmute(r);
+            // Check the results.
+            for r in r {
+                vals.insert(r.to_bits());
+                // Ensure the relative error is less than 2^-12.
+                let rel_error = (r - exact) / exact;
+                let log_error = rel_error.abs().log2();
+                assert!(
+                    rel_error == 0.0 || log_error < -12.0,
+                    "got an error of {rel_error} = 2^{log_error}"
+                );
+            }
+        }
+    }
+    // Ensure we saw a bunch of different results.
+    assert!(vals.len() >= 50);
+}
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs b/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs
index abe08f2cd22..7352784ac7a 100644
--- a/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs
@@ -14,9 +14,11 @@ fn main() {
     foo(&arr[0]);
 
     let pair = (Cell::new(1), 1);
-    // TODO: Ideally, this would result in UB since the second element
-    // in `pair` is Frozen.  We would need some way to express a
-    // "shared reference with permission to access surrounding
-    // interior mutable data".
     foo(&pair.0);
+
+    // As long as the "inside" part is `!Freeze`, the permission to mutate the "outside" is preserved.
+    let pair = (Cell::new(()), 1);
+    let x = &pair.0;
+    let ptr = (&raw const *x).cast::<i32>().cast_mut();
+    unsafe { ptr.write(0) };
 }
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index f021d5194cd..b7286d9a367 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -60,6 +60,7 @@ fn build_native_lib(target: &str) -> PathBuf {
             native_lib_path.to_str().unwrap(),
             // FIXME: Automate gathering of all relevant C source files in the directory.
             "tests/native-lib/scalar_arguments.c",
+            "tests/native-lib/aggregate_arguments.c",
             "tests/native-lib/ptr_read_access.c",
             "tests/native-lib/ptr_write_access.c",
             // Ensure we notice serious problems in the C code.
diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs
index 1a3cd067c04..4757a5a268c 100644
--- a/src/tools/miri/tests/utils/libc.rs
+++ b/src/tools/miri/tests/utils/libc.rs
@@ -34,10 +34,7 @@ pub unsafe fn write_all(
         if res < 0 {
             return res;
         }
-        if res == 0 {
-            // EOF?
-            break;
-        }
+        // Apparently a return value of 0 is just a short write, nothing special (unlike reads).
         written_so_far += res as libc::size_t;
     }
     return written_so_far as libc::ssize_t;
diff --git a/src/tools/run-make-support/src/external_deps/cargo.rs b/src/tools/run-make-support/src/external_deps/cargo.rs
index 8da9f002c41..3f2d0ce14e3 100644
--- a/src/tools/run-make-support/src/external_deps/cargo.rs
+++ b/src/tools/run-make-support/src/external_deps/cargo.rs
@@ -1,11 +1,17 @@
 use crate::command::Command;
-use crate::env_var;
 use crate::util::set_host_compiler_dylib_path;
 
-/// Returns a command that can be used to invoke cargo. The cargo is provided by compiletest
-/// through the `CARGO` env var.
+/// Returns a command that can be used to invoke in-tree cargo. The cargo is provided by compiletest
+/// through the `CARGO` env var, and is **only** available for the `run-make-cargo` test suite.
 pub fn cargo() -> Command {
-    let mut cmd = Command::new(env_var("CARGO"));
+    let cargo_path = std::env::var("CARGO").unwrap_or_else(|e| {
+        panic!(
+            "in-tree `cargo` should be available for `run-make-cargo` test suite, but not \
+            `run-make` test suite: {e}"
+        )
+    });
+
+    let mut cmd = Command::new(cargo_path);
     set_host_compiler_dylib_path(&mut cmd);
     cmd
 }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 191e205f257..fef75401d94 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -1,7 +1,8 @@
 //! `run-make-support` is a support library for run-make tests. It provides command wrappers and
 //! convenience utility functions to help test writers reduce duplication. The support library
-//! notably is built via cargo: this means that if your test wants some non-trivial utility, such
-//! as `object` or `wasmparser`, they can be re-exported and be made available through this library.
+//! notably is built via bootstrap cargo: this means that if your test wants some non-trivial
+//! utility, such as `object` or `wasmparser`, they can be re-exported and be made available through
+//! this library.
 
 #![warn(unreachable_pub)]
 
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index 42feae8c208..5062c2597f1 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -71,22 +71,28 @@ fn main() -> Result<(), ()> {
     let mut command = Command::new(&config.nodejs);
 
     command
-        .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js"))
+        .arg(local_node_modules.join(".bin/browser-ui-test"))
         .arg("--jobs")
         .arg(&config.jobs)
-        .arg("--doc-folder")
+        .arg("--variable")
+        .arg("DOC_PATH")
         .arg(config.out_dir.join("doc"))
-        .arg("--tests-folder")
-        .arg(config.rust_src.join("tests/rustdoc-gui"));
+        .arg("--allow-file-access-from-files")
+        .arg("--display-format")
+        .arg("compact");
 
     if local_node_modules.exists() {
-        // Link the local node_modules if exists.
+        // Link the local node_modules if it exists.
         // This is useful when we run rustdoc-gui-test from outside of the source root.
         command.env("NODE_PATH", local_node_modules);
     }
 
-    for file in &config.goml_files {
-        command.arg("--file").arg(file);
+    if config.goml_files.is_empty() {
+        command.arg("--test-folder").arg(config.rust_src.join("tests/rustdoc-gui"));
+    } else {
+        for file in &config.goml_files {
+            command.arg("--test-file").arg(config.rust_src.join("tests/rustdoc-gui").join(file));
+        }
     }
 
     command.args(&config.test_args);
diff --git a/src/tools/rustdoc-gui/.eslintrc.js b/src/tools/rustdoc-gui/.eslintrc.js
deleted file mode 100644
index 3eccbc74cb9..00000000000
--- a/src/tools/rustdoc-gui/.eslintrc.js
+++ /dev/null
@@ -1,96 +0,0 @@
-module.exports = {
-    "env": {
-        "browser": true,
-        "node": true,
-        "es6": true
-    },
-    "extends": "eslint:recommended",
-    "parserOptions": {
-        "ecmaVersion": 2019,
-        "sourceType": "module"
-    },
-    "rules": {
-        "linebreak-style": [
-            "error",
-            "unix"
-        ],
-        "semi": [
-            "error",
-            "always"
-        ],
-        "quotes": [
-            "error",
-            "double"
-        ],
-        "linebreak-style": [
-            "error",
-            "unix"
-        ],
-        "no-trailing-spaces": "error",
-        "no-var": ["error"],
-        "prefer-const": ["error"],
-        "prefer-arrow-callback": ["error"],
-        "brace-style": [
-            "error",
-            "1tbs",
-            { "allowSingleLine": false }
-        ],
-        "keyword-spacing": [
-            "error",
-            { "before": true, "after": true }
-        ],
-        "arrow-spacing": [
-            "error",
-            { "before": true, "after": true }
-        ],
-        "key-spacing": [
-            "error",
-            { "beforeColon": false, "afterColon": true, "mode": "strict" }
-        ],
-        "func-call-spacing": ["error", "never"],
-        "space-infix-ops": "error",
-        "space-before-function-paren": ["error", "never"],
-        "space-before-blocks": "error",
-        "comma-dangle": ["error", "always-multiline"],
-        "comma-style": ["error", "last"],
-        "max-len": ["error", { "code": 100, "tabWidth": 4 }],
-        "eol-last": ["error", "always"],
-        "arrow-parens": ["error", "as-needed"],
-        "no-unused-vars": [
-            "error",
-            {
-                "argsIgnorePattern": "^_",
-                "varsIgnorePattern": "^_"
-            }
-        ],
-        "eqeqeq": "error",
-        "no-const-assign": "error",
-        "no-debugger": "error",
-        "no-dupe-args": "error",
-        "no-dupe-else-if": "error",
-        "no-dupe-keys": "error",
-        "no-duplicate-case": "error",
-        "no-ex-assign": "error",
-        "no-fallthrough": "error",
-        "no-invalid-regexp": "error",
-        "no-import-assign": "error",
-        "no-self-compare": "error",
-        "no-template-curly-in-string": "error",
-        "block-scoped-var": "error",
-        "guard-for-in": "error",
-        "no-alert": "error",
-        "no-confusing-arrow": "error",
-        "no-div-regex": "error",
-        "no-floating-decimal": "error",
-        "no-implicit-globals": "error",
-        "no-implied-eval": "error",
-        "no-label-var": "error",
-        "no-lonely-if": "error",
-        "no-mixed-operators": "error",
-        "no-multi-assign": "error",
-        "no-return-assign": "error",
-        "no-script-url": "error",
-        "no-sequences": "error",
-        "no-div-regex": "error",
-    }
-};
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
deleted file mode 100644
index 9dc32f335a8..00000000000
--- a/src/tools/rustdoc-gui/tester.js
+++ /dev/null
@@ -1,309 +0,0 @@
-// This package needs to be install:
-//
-// ```
-// npm install browser-ui-test
-// ```
-
-const fs = require("fs");
-const path = require("path");
-const os = require("os");
-const {Options, runTest} = require("browser-ui-test");
-
-// If a test fails or errors, we will retry it two more times in case it was a flaky failure.
-const NB_RETRY = 3;
-
-function showHelp() {
-    console.log("rustdoc-js options:");
-    console.log("  --doc-folder [PATH]        : location of the generated doc folder");
-    console.log("  --file [PATH]              : file to run (can be repeated)");
-    console.log("  --debug                    : show extra information about script run");
-    console.log("  --show-text                : render font in pages");
-    console.log("  --no-headless              : disable headless mode");
-    console.log("  --help                     : show this message then quit");
-    console.log("  --tests-folder [PATH]      : location of the .GOML tests folder");
-    console.log("  --jobs [NUMBER]            : number of threads to run tests on");
-    console.log("  --executable-path [PATH]   : path of the browser's executable to be used");
-}
-
-function isNumeric(s) {
-    return /^\d+$/.test(s);
-}
-
-function parseOptions(args) {
-    const opts = {
-        "doc_folder": "",
-        "tests_folder": "",
-        "files": [],
-        "debug": false,
-        "show_text": false,
-        "no_headless": false,
-        "jobs": -1,
-        "executable_path": null,
-    };
-    const correspondences = {
-        "--doc-folder": "doc_folder",
-        "--tests-folder": "tests_folder",
-        "--debug": "debug",
-        "--show-text": "show_text",
-        "--no-headless": "no_headless",
-        "--executable-path": "executable_path",
-    };
-
-    for (let i = 0; i < args.length; ++i) {
-        const arg = args[i];
-        if (arg === "--doc-folder"
-            || arg === "--tests-folder"
-            || arg === "--file"
-            || arg === "--jobs"
-            || arg === "--executable-path") {
-            i += 1;
-            if (i >= args.length) {
-                console.log("Missing argument after `" + arg + "` option.");
-                return null;
-            }
-            const arg_value = args[i];
-            if (arg === "--jobs") {
-                if (!isNumeric(arg_value)) {
-                    console.log(
-                        "`--jobs` option expects a positive number, found `" + arg_value + "`");
-                    return null;
-                }
-                opts["jobs"] = parseInt(arg_value);
-            } else if (arg !== "--file") {
-                opts[correspondences[arg]] = arg_value;
-            } else {
-                opts["files"].push(arg_value);
-            }
-        } else if (arg === "--help") {
-            showHelp();
-            process.exit(0);
-        } else if (correspondences[arg]) {
-            opts[correspondences[arg]] = true;
-        } else {
-            console.log("Unknown option `" + arg + "`.");
-            console.log("Use `--help` to see the list of options");
-            return null;
-        }
-    }
-    if (opts["tests_folder"].length < 1) {
-        console.log("Missing `--tests-folder` option.");
-    } else if (opts["doc_folder"].length < 1) {
-        console.log("Missing `--doc-folder` option.");
-    } else {
-        return opts;
-    }
-    return null;
-}
-
-/// Print single char status information without \n
-function char_printer(n_tests) {
-    const max_per_line = 10;
-    let current = 0;
-    return {
-        successful: function() {
-            current += 1;
-            if (current % max_per_line === 0) {
-                process.stdout.write(`. (${current}/${n_tests})${os.EOL}`);
-            } else {
-                process.stdout.write(".");
-            }
-        },
-        erroneous: function() {
-            current += 1;
-            if (current % max_per_line === 0) {
-                process.stderr.write(`F (${current}/${n_tests})${os.EOL}`);
-            } else {
-                process.stderr.write("F");
-            }
-        },
-        finish: function() {
-            if (current % max_per_line === 0) {
-                // Don't output if we are already at a matching line end
-                console.log("");
-            } else {
-                const spaces = " ".repeat(max_per_line - (current % max_per_line));
-                process.stdout.write(`${spaces} (${current}/${n_tests})${os.EOL}${os.EOL}`);
-            }
-        },
-    };
-}
-
-// Sort array by .file_name property
-function by_filename(a, b) {
-    return a.file_name - b.file_name;
-}
-
-async function runTests(opts, framework_options, files, results, status_bar, showTestFailures) {
-    const tests_queue = [];
-
-    for (const testPath of files) {
-        const callback = runTest(testPath, {"options": framework_options})
-            .then(out => {
-                const [output, nb_failures] = out;
-                results[nb_failures === 0 ? "successful" : "failed"].push({
-                    file_name: testPath,
-                    output: output,
-                });
-                if (nb_failures === 0) {
-                    status_bar.successful();
-                } else if (showTestFailures) {
-                    status_bar.erroneous();
-                }
-            })
-            .catch(err => {
-                results.errored.push({
-                    file_name: testPath,
-                    output: err,
-                });
-                if (showTestFailures) {
-                    status_bar.erroneous();
-                }
-            })
-            .finally(() => {
-                // We now remove the promise from the tests_queue.
-                tests_queue.splice(tests_queue.indexOf(callback), 1);
-            });
-        tests_queue.push(callback);
-        if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) {
-            await Promise.race(tests_queue);
-        }
-    }
-    if (tests_queue.length > 0) {
-        await Promise.all(tests_queue);
-    }
-}
-
-function createEmptyResults() {
-    return {
-        successful: [],
-        failed: [],
-        errored: [],
-    };
-}
-
-async function main(argv) {
-    const opts = parseOptions(argv.slice(2));
-    if (opts === null) {
-        process.exit(1);
-    }
-
-    // Print successful tests too
-    let debug = false;
-    // Run tests in sequentially
-    let headless = true;
-    const framework_options = new Options();
-    try {
-        // This is more convenient that setting fields one by one.
-        const args = [
-            "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
-            "--allow-file-access-from-files",
-        ];
-        if (opts["debug"]) {
-            debug = true;
-            args.push("--debug");
-        }
-        if (opts["show_text"]) {
-            args.push("--show-text");
-        }
-        if (opts["no_headless"]) {
-            args.push("--no-headless");
-            headless = false;
-        }
-        if (opts["executable_path"] !== null) {
-            args.push("--executable-path");
-            args.push(opts["executable_path"]);
-        }
-        framework_options.parseArguments(args);
-    } catch (error) {
-        console.error(`invalid argument: ${error}`);
-        process.exit(1);
-    }
-
-    let files;
-    if (opts["files"].length === 0) {
-        files = fs.readdirSync(opts["tests_folder"]);
-    } else {
-        files = opts["files"];
-    }
-    files = files.filter(file => path.extname(file) === ".goml");
-    if (files.length === 0) {
-        console.error("rustdoc-gui: No test selected");
-        process.exit(2);
-    }
-    files.forEach((file_name, index) => {
-        files[index] = path.join(opts["tests_folder"], file_name);
-    });
-    files.sort();
-
-    if (!headless) {
-        opts["jobs"] = 1;
-        console.log("`--no-headless` option is active, disabling concurrency for running tests.");
-    }
-
-    if (opts["jobs"] < 1) {
-        const len = files.length;
-        console.log(
-            `Running ${len} rustdoc-gui (UNBOUNDED concurrency; use "-j#" for a limit) ...`,
-        );
-        process.setMaxListeners(files.length + 1);
-    } else if (headless) {
-        console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
-        process.setMaxListeners(opts["jobs"] + 1);
-    } else {
-        console.log(`Running ${files.length} rustdoc-gui ...`);
-    }
-
-    const originalFilesLen = files.length;
-    const results = createEmptyResults();
-    const status_bar = char_printer(files.length);
-
-    let new_results;
-    for (let it = 0; it < NB_RETRY && files.length > 0; ++it) {
-        new_results = createEmptyResults();
-        await runTests(opts, framework_options, files, new_results, status_bar, it + 1 >= NB_RETRY);
-        Array.prototype.push.apply(results.successful, new_results.successful);
-        // We generate the new list of files with the previously failing tests.
-        files = Array.prototype.concat(new_results.failed, new_results.errored).map(
-            f => f["file_name"]);
-        if (files.length > originalFilesLen / 2) {
-            // If we have too many failing tests, it's very likely not flaky failures anymore so
-            // no need to retry.
-            break;
-        }
-    }
-
-    status_bar.finish();
-
-    Array.prototype.push.apply(results.failed, new_results.failed);
-    Array.prototype.push.apply(results.errored, new_results.errored);
-
-    if (debug) {
-        results.successful.sort(by_filename);
-        results.successful.forEach(r => {
-            console.log(r.output);
-        });
-    }
-
-    if (results.failed.length > 0) {
-        console.log("");
-        results.failed.sort(by_filename);
-        results.failed.forEach(r => {
-            console.log(r.file_name, r.output);
-        });
-    }
-    if (results.errored.length > 0) {
-        console.log(os.EOL);
-        // print run errors on the bottom so developers see them better
-        results.errored.sort(by_filename);
-        results.errored.forEach(r => {
-            console.error(r.file_name, r.output);
-        });
-    }
-
-    if (results.failed.length > 0 || results.errored.length > 0) {
-        process.exit(1);
-    }
-    process.exit(0);
-}
-
-main(process.argv);
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 560f11ecf50..fee48bea144 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -80,7 +80,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>,
     ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]),
     ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]),
     ("src/tools/test-float-parse", EXCEPTIONS, None, &[]),
-    ("tests/run-make/uefi-qemu/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]),
+    ("tests/run-make-cargo/uefi-qemu/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]),
     // tidy-alphabetical-end
 ];
 
diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs
index 31169ec5967..321ef65117e 100644
--- a/src/tools/tidy/src/extra_checks/mod.rs
+++ b/src/tools/tidy/src/extra_checks/mod.rs
@@ -303,7 +303,7 @@ fn check_impl(
     }
 
     if js_lint {
-        rustdoc_js::lint(outdir, librustdoc_path, tools_path)?;
+        rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless)?;
         rustdoc_js::es_check(outdir, librustdoc_path)?;
     }
 
@@ -720,21 +720,19 @@ impl ExtraCheckArg {
         if !self.auto {
             return true;
         }
-        let ext = match self.lang {
-            ExtraCheckLang::Py => ".py",
-            ExtraCheckLang::Cpp => ".cpp",
-            ExtraCheckLang::Shell => ".sh",
-            ExtraCheckLang::Js => ".js",
+        let exts: &[&str] = match self.lang {
+            ExtraCheckLang::Py => &[".py"],
+            ExtraCheckLang::Cpp => &[".cpp"],
+            ExtraCheckLang::Shell => &[".sh"],
+            ExtraCheckLang::Js => &[".js", ".ts"],
             ExtraCheckLang::Spellcheck => {
-                for dir in SPELLCHECK_DIRS {
-                    if Path::new(filepath).starts_with(dir) {
-                        return true;
-                    }
+                if SPELLCHECK_DIRS.iter().any(|dir| Path::new(filepath).starts_with(dir)) {
+                    return true;
                 }
-                return false;
+                &[]
             }
         };
-        filepath.ends_with(ext)
+        exts.iter().any(|ext| filepath.ends_with(ext))
     }
 
     fn has_supported_kind(&self) -> bool {
diff --git a/src/tools/tidy/src/extra_checks/rustdoc_js.rs b/src/tools/tidy/src/extra_checks/rustdoc_js.rs
index 7708b128e23..a6c66b8be80 100644
--- a/src/tools/tidy/src/extra_checks/rustdoc_js.rs
+++ b/src/tools/tidy/src/extra_checks/rustdoc_js.rs
@@ -40,13 +40,18 @@ fn rustdoc_js_files(librustdoc_path: &Path) -> Vec<PathBuf> {
     return files;
 }
 
-fn run_eslint(outdir: &Path, args: &[PathBuf], config_folder: PathBuf) -> Result<(), super::Error> {
-    let mut child = spawn_cmd(
-        Command::new(node_module_bin(outdir, "eslint"))
-            .arg("-c")
-            .arg(config_folder.join(".eslintrc.js"))
-            .args(args),
-    )?;
+fn run_eslint(
+    outdir: &Path,
+    args: &[PathBuf],
+    config_folder: PathBuf,
+    bless: bool,
+) -> Result<(), super::Error> {
+    let mut cmd = Command::new(node_module_bin(outdir, "eslint"));
+    if bless {
+        cmd.arg("--fix");
+    }
+    cmd.arg("-c").arg(config_folder.join(".eslintrc.js")).args(args);
+    let mut child = spawn_cmd(&mut cmd)?;
     match child.wait() {
         Ok(exit_status) => {
             if exit_status.success() {
@@ -62,16 +67,17 @@ pub(super) fn lint(
     outdir: &Path,
     librustdoc_path: &Path,
     tools_path: &Path,
+    bless: bool,
 ) -> Result<(), super::Error> {
     let files_to_check = rustdoc_js_files(librustdoc_path);
     println!("Running eslint on rustdoc JS files");
-    run_eslint(outdir, &files_to_check, librustdoc_path.join("html/static"))?;
+    run_eslint(outdir, &files_to_check, librustdoc_path.join("html/static"), bless)?;
 
-    run_eslint(outdir, &[tools_path.join("rustdoc-js/tester.js")], tools_path.join("rustdoc-js"))?;
     run_eslint(
         outdir,
-        &[tools_path.join("rustdoc-gui/tester.js")],
-        tools_path.join("rustdoc-gui"),
+        &[tools_path.join("rustdoc-js/tester.js")],
+        tools_path.join("rustdoc-js"),
+        bless,
     )?;
     Ok(())
 }
diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs
index 305a0b4d264..6f25ed616fa 100644
--- a/src/tools/tidy/src/triagebot.rs
+++ b/src/tools/tidy/src/triagebot.rs
@@ -19,7 +19,12 @@ pub fn check(path: &Path, bad: &mut bool) {
 
     // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"]
     if let Some(Value::Table(mentions)) = config.get("mentions") {
-        for path_str in mentions.keys() {
+        for (entry_key, entry_val) in mentions.iter() {
+            // If the type is set to something other than "filename", then this is not a path.
+            if entry_val.get("type").is_some_and(|t| t.as_str().unwrap_or_default() != "filename") {
+                continue;
+            }
+            let path_str = entry_key;
             // Remove quotes from the path
             let clean_path = path_str.trim_matches('"');
             let full_path = path.join(clean_path);
diff --git a/src/tools/unicode-table-generator/src/cascading_map.rs b/src/tools/unicode-table-generator/src/cascading_map.rs
index 78a7bba3208..56e6401908d 100644
--- a/src/tools/unicode-table-generator/src/cascading_map.rs
+++ b/src/tools/unicode-table-generator/src/cascading_map.rs
@@ -64,6 +64,7 @@ impl RawEmitter {
 
         writeln!(&mut self.file, "#[inline]").unwrap();
         writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap();
+        writeln!(&mut self.file, "    debug_assert!(!c.is_ascii());").unwrap();
         writeln!(&mut self.file, "    match c as u32 >> 8 {{").unwrap();
         for arm in arms {
             writeln!(&mut self.file, "        {arm},").unwrap();
diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs
index 9399021df76..ded9205ffc4 100644
--- a/src/tools/unicode-table-generator/src/main.rs
+++ b/src/tools/unicode-table-generator/src/main.rs
@@ -195,6 +195,7 @@ fn load_data() -> UnicodeData {
                 .into_iter()
                 .flatten()
                 .flat_map(|cp| cp.scalar())
+                .filter(|c| !c.is_ascii())
                 .map(u32::from)
                 .collect::<Vec<_>>();
             (prop, ranges_from_set(&codepoints))
@@ -228,7 +229,7 @@ fn main() {
 
     let mut table_file = String::new();
     table_file.push_str(
-        "///! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually!\n",
+        "//! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually!\n",
     );
 
     let mut total_bytes = 0;
diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs
index 03ed9499e26..297965615c1 100644
--- a/src/tools/unicode-table-generator/src/raw_emitter.rs
+++ b/src/tools/unicode-table-generator/src/raw_emitter.rs
@@ -98,6 +98,7 @@ impl RawEmitter {
         self.blank_line();
 
         writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap();
+        writeln!(&mut self.file, "    debug_assert!(!c.is_ascii());").unwrap();
         if first_code_point > 0x7f {
             writeln!(&mut self.file, "    (c as u32) >= {first_code_point:#04x} &&").unwrap();
         }
diff --git a/src/tools/unicode-table-generator/src/skiplist.rs b/src/tools/unicode-table-generator/src/skiplist.rs
index 34c9802e122..660a8f342f7 100644
--- a/src/tools/unicode-table-generator/src/skiplist.rs
+++ b/src/tools/unicode-table-generator/src/skiplist.rs
@@ -99,6 +99,7 @@ impl RawEmitter {
         if first_code_point > 0x7f {
             writeln!(&mut self.file, "#[inline]").unwrap();
             writeln!(&mut self.file, "pub fn lookup(c: char) -> bool {{").unwrap();
+            writeln!(&mut self.file, "    debug_assert!(!c.is_ascii());").unwrap();
             writeln!(&mut self.file, "    (c as u32) >= {first_code_point:#04x} && lookup_slow(c)")
                 .unwrap();
             writeln!(&mut self.file, "}}").unwrap();
@@ -107,6 +108,7 @@ impl RawEmitter {
             writeln!(&mut self.file, "fn lookup_slow(c: char) -> bool {{").unwrap();
         } else {
             writeln!(&mut self.file, "pub fn lookup(c: char) -> bool {{").unwrap();
+            writeln!(&mut self.file, "    debug_assert!(!c.is_ascii());").unwrap();
         }
         writeln!(&mut self.file, "    const {{").unwrap();
         writeln!(
diff --git a/tests/assembly-llvm/breakpoint.rs b/tests/assembly-llvm/breakpoint.rs
index e0cc2d1eebb..d119b68e899 100644
--- a/tests/assembly-llvm/breakpoint.rs
+++ b/tests/assembly-llvm/breakpoint.rs
@@ -9,6 +9,7 @@
 // CHECK-LABEL: use_bp
 // aarch64: brk #0xf000
 // x86_64: int3
+#[inline(never)]
 pub fn use_bp() {
     core::arch::breakpoint();
 }
diff --git a/tests/assembly-llvm/loongarch-float-struct-abi.rs b/tests/assembly-llvm/loongarch-float-struct-abi.rs
new file mode 100644
index 00000000000..4991004fc05
--- /dev/null
+++ b/tests/assembly-llvm/loongarch-float-struct-abi.rs
@@ -0,0 +1,134 @@
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ compile-flags: -Copt-level=3 --target loongarch64-unknown-linux-gnu
+//@ needs-llvm-components: loongarch
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C, align(64))]
+struct Aligned(f64);
+
+#[repr(C)]
+struct Padded(u8, Aligned);
+
+#[repr(C, packed)]
+struct Packed(u8, f32);
+
+impl Copy for Aligned {}
+impl Copy for Padded {}
+impl Copy for Packed {}
+
+extern "C" {
+    fn take_padded(x: Padded);
+    fn get_padded() -> Padded;
+    fn take_packed(x: Packed);
+    fn get_packed() -> Packed;
+}
+
+// CHECK-LABEL: pass_padded
+#[unsafe(no_mangle)]
+extern "C" fn pass_padded(out: &mut Padded, x: Padded) {
+    // CHECK: st.b $a1, $a0, 0
+    // CHECK-NEXT: fst.d $fa0, $a0, 64
+    // CHECK-NEXT: ret
+    *out = x;
+}
+
+// CHECK-LABEL: ret_padded
+#[unsafe(no_mangle)]
+extern "C" fn ret_padded(x: &Padded) -> Padded {
+    // CHECK: fld.d $fa0, $a0, 64
+    // CHECK-NEXT: ld.b $a0, $a0, 0
+    // CHECK-NEXT: ret
+    *x
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn call_padded(x: &Padded) {
+    // CHECK: fld.d $fa0, $a0, 64
+    // CHECK-NEXT: ld.b $a0, $a0, 0
+    // CHECK-NEXT: pcaddu18i $t8, %call36(take_padded)
+    // CHECK-NEXT: jr $t8
+    unsafe {
+        take_padded(*x);
+    }
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn receive_padded(out: &mut Padded) {
+    // CHECK: addi.d $sp, $sp, -16
+    // CHECK-NEXT: .cfi_def_cfa_offset 16
+    // CHECK-NEXT: st.d $ra, $sp, [[#%d,RA_SPILL:]]
+    // CHECK-NEXT: st.d [[TEMP:.*]], $sp, [[#%d,TEMP_SPILL:]]
+    // CHECK-NEXT: .cfi_offset 1, [[#%d,RA_SPILL - 16]]
+    // CHECK-NEXT: .cfi_offset [[#%d,TEMP_NUM:]], [[#%d,TEMP_SPILL - 16]]
+    // CHECK-NEXT: move [[TEMP]], $a0
+    // CHECK-NEXT: pcaddu18i $ra, %call36(get_padded)
+    // CHECK-NEXT: jirl $ra, $ra, 0
+    // CHECK-NEXT: st.b $a0, [[TEMP]], 0
+    // CHECK-NEXT: fst.d $fa0, [[TEMP]], 64
+    // CHECK-NEXT: ld.d [[TEMP]], $sp, [[#%d,TEMP_SPILL]]
+    // CHECK-NEXT: ld.d $ra, $sp, [[#%d,RA_SPILL]]
+    // CHECK: addi.d $sp, $sp, 16
+    // CHECK: ret
+    unsafe {
+        *out = get_padded();
+    }
+}
+
+// CHECK-LABEL: pass_packed
+#[unsafe(no_mangle)]
+extern "C" fn pass_packed(out: &mut Packed, x: Packed) {
+    // CHECK: st.b $a1, $a0, 0
+    // CHECK-NEXT: fst.s $fa0, $a0, 1
+    // CHECK-NEXT: ret
+    *out = x;
+}
+
+// CHECK-LABEL: ret_packed
+#[unsafe(no_mangle)]
+extern "C" fn ret_packed(x: &Packed) -> Packed {
+    // CHECK: fld.s $fa0, $a0, 1
+    // CHECK-NEXT: ld.b $a0, $a0, 0
+    // CHECK-NEXT: ret
+    *x
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn call_packed(x: &Packed) {
+    // CHECK: fld.s $fa0, $a0, 1
+    // CHECK-NEXT: ld.b $a0, $a0, 0
+    // CHECK-NEXT: pcaddu18i $t8, %call36(take_packed)
+    // CHECK-NEXT: jr $t8
+    unsafe {
+        take_packed(*x);
+    }
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn receive_packed(out: &mut Packed) {
+    // CHECK: addi.d $sp, $sp, -16
+    // CHECK-NEXT: .cfi_def_cfa_offset 16
+    // CHECK-NEXT: st.d $ra, $sp, [[#%d,RA_SPILL:]]
+    // CHECK-NEXT: st.d [[TEMP:.*]], $sp, [[#%d,TEMP_SPILL:]]
+    // CHECK-NEXT: .cfi_offset 1, [[#%d,RA_SPILL - 16]]
+    // CHECK-NEXT: .cfi_offset [[#%d,TEMP_NUM:]], [[#%d,TEMP_SPILL - 16]]
+    // CHECK-NEXT: move [[TEMP]], $a0
+    // CHECK-NEXT: pcaddu18i $ra, %call36(get_packed)
+    // CHECK-NEXT: jirl $ra, $ra, 0
+    // CHECK-NEXT: st.b $a0, [[TEMP]], 0
+    // CHECK-NEXT: fst.s $fa0, [[TEMP]], 1
+    // CHECK-NEXT: ld.d [[TEMP]], $sp, [[#%d,TEMP_SPILL]]
+    // CHECK-NEXT: ld.d $ra, $sp, [[#%d,RA_SPILL]]
+    // CHECK: addi.d $sp, $sp, 16
+    // CHECK: ret
+    unsafe {
+        *out = get_packed();
+    }
+}
diff --git a/tests/assembly-llvm/simd/reduce-fadd-unordered.rs b/tests/assembly-llvm/simd/reduce-fadd-unordered.rs
index e872826f6ef..fdd03639da0 100644
--- a/tests/assembly-llvm/simd/reduce-fadd-unordered.rs
+++ b/tests/assembly-llvm/simd/reduce-fadd-unordered.rs
@@ -16,6 +16,7 @@ use std::simd::*;
 // It would emit about an extra fadd, depending on the architecture.
 
 // CHECK-LABEL: reduce_fadd_negative_zero
+#[inline(never)]
 pub unsafe fn reduce_fadd_negative_zero(v: f32x4) -> f32 {
     // x86_64: addps
     // x86_64-NEXT: movshdup
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index da880100a10..4f4c653cb46 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -179,7 +179,14 @@ impl Add<isize> for isize {
 
 #[lang = "sync"]
 trait Sync {}
-impl Sync for u8 {}
+impl_marker_trait!(
+    Sync => [
+        char, bool,
+        isize, i8, i16, i32, i64, i128,
+        usize, u8, u16, u32, u64, u128,
+        f16, f32, f64, f128,
+    ]
+);
 
 #[lang = "drop_in_place"]
 fn drop_in_place<T>(_: *mut T) {}
diff --git a/tests/codegen-llvm/amdgpu-addrspacecast.rs b/tests/codegen-llvm/amdgpu-addrspacecast.rs
index 7fe630a7efa..829133de00d 100644
--- a/tests/codegen-llvm/amdgpu-addrspacecast.rs
+++ b/tests/codegen-llvm/amdgpu-addrspacecast.rs
@@ -16,3 +16,12 @@ pub fn ref_of_local(f: fn(&i32)) {
     let i = 0;
     f(&i);
 }
+
+// CHECK-LABEL: @ref_of_global
+// CHECK: addrspacecast (ptr addrspace(1) @I to ptr)
+#[no_mangle]
+pub fn ref_of_global(f: fn(&i32)) {
+    #[no_mangle]
+    static I: i32 = 0;
+    f(&I);
+}
diff --git a/tests/codegen-llvm/cast-target-abi.rs b/tests/codegen-llvm/cast-target-abi.rs
index 28d3ad5f61c..090de00df93 100644
--- a/tests/codegen-llvm/cast-target-abi.rs
+++ b/tests/codegen-llvm/cast-target-abi.rs
@@ -171,7 +171,15 @@ pub extern "C" fn receives_doubledouble(x: DoubleDouble) {
 
     // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
 
-    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE:%.+]], 0
+    // loongarch64: [[ABI_VALUE_1:%.+]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE:%.+]], 1
+    // loongarch64: store double [[ABI_VALUE_0]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: store double [[ABI_VALUE_1]], ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
+    // powerpc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
 }
@@ -190,7 +198,11 @@ pub extern "C" fn returns_doubledouble() -> DoubleDouble {
     // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
-    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = load double, ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: [[ABI_VALUE_1:%.+]] = load double, ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_2:%.+]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[ABI_VALUE_0]], 0
+    // loongarch64: [[ABI_VALUE:%.+]] = insertvalue { double, double } [[ABI_VALUE_2]], double [[ABI_VALUE_1]], 1
     // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
@@ -269,7 +281,11 @@ pub extern "C" fn receives_doublefloat(x: DoubleFloat) {
     // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
 
     // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
-    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = extractvalue { double, float } [[ABI_VALUE]], 0
+    // loongarch64: [[ABI_VALUE_1:%.+]] = extractvalue { double, float } [[ABI_VALUE]], 1
+    // loongarch64: store double [[ABI_VALUE_0]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: store float [[ABI_VALUE_1]], ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
     // powerpc64:   store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
@@ -297,7 +313,11 @@ pub extern "C" fn returns_doublefloat() -> DoubleFloat {
     // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
-    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = load double, ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: [[ABI_VALUE_1:%.+]] = load float, ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_2:%.+]] = insertvalue [[ABI_TYPE:{ double, float }]] poison, double [[ABI_VALUE_0]], 0
+    // loongarch64: [[ABI_VALUE:%.+]] = insertvalue { double, float } [[ABI_VALUE_2]], float [[ABI_VALUE_1]], 1
     // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
@@ -429,7 +449,11 @@ pub fn call_doubledouble() {
     // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
 
     // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
-    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = load double, ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: [[ABI_VALUE_1:%.+]] = load double, ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_2:%.+]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[ABI_VALUE_0]], 0
+    // loongarch64: [[ABI_VALUE:%.+]] = insertvalue { double, double } [[ABI_VALUE_2]], double [[ABI_VALUE_1]], 1
     // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
@@ -465,7 +489,11 @@ pub fn return_doubledouble() -> DoubleDouble {
     // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble()
 
     // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
-    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = extractvalue { double, double } [[ABI_VALUE]], 0
+    // loongarch64: [[ABI_VALUE_1:%.+]] = extractvalue { double, double } [[ABI_VALUE]], 1
+    // loongarch64: store double [[ABI_VALUE_0]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: store double [[ABI_VALUE_1]], ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
     // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
@@ -500,7 +528,11 @@ pub fn call_doublefloat() {
     // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
 
     // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
-    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = load double, ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: [[ABI_VALUE_1:%.+]] = load float, ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_2:%.+]] = insertvalue [[ABI_TYPE:{ double, float }]] poison, double [[ABI_VALUE_0]], 0
+    // loongarch64: [[ABI_VALUE:%.+]] = insertvalue { double, float } [[ABI_VALUE_2]], float [[ABI_VALUE_1]], 1
     // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
@@ -540,7 +572,11 @@ pub fn return_doublefloat() -> DoubleFloat {
     // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doublefloat()
 
     // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
-    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE_0:%.+]] = extractvalue { double, float } [[ABI_VALUE]], 0
+    // loongarch64: [[ABI_VALUE_1:%.+]] = extractvalue { double, float } [[ABI_VALUE]], 1
+    // loongarch64: store double [[ABI_VALUE_0]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_ALLOCA_1:%.+]] = getelementptr inbounds i8, ptr [[ABI_ALLOCA]], i64 8
+    // loongarch64: store float [[ABI_VALUE_1]], ptr [[ABI_ALLOCA_1]], align [[ABI_ALIGN]]
     // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
diff --git a/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs b/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs
index d059a3d0a73..7b5679c3f4d 100644
--- a/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs
+++ b/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs
@@ -18,3 +18,8 @@ pub fn stem_fn() -> String {
 fn inner() -> String {
     String::from("test")
 }
+
+// This function's optimized MIR contains a call, but it is to an intrinsic.
+pub fn leaf_with_intrinsic(a: &[u64; 2], b: &[u64; 2]) -> bool {
+    a == b
+}
diff --git a/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs b/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs
index 37132312ca9..5e7912791ad 100644
--- a/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs
+++ b/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs
@@ -18,3 +18,10 @@ pub fn stem_outer() -> String {
     // CHECK: call {{.*}}stem_fn
     leaf::stem_fn()
 }
+
+// Check that we inline functions that call intrinsics
+#[no_mangle]
+pub fn leaf_with_intrinsic_outer(a: &[u64; 2], b: &[u64; 2]) -> bool {
+    // CHECK-NOT: call {{.*}}leaf_with_intrinsic
+    leaf::leaf_with_intrinsic(a, b)
+}
diff --git a/tests/codegen-llvm/default-visibility.rs b/tests/codegen-llvm/default-visibility.rs
index 88ff9fee254..28238e5ef12 100644
--- a/tests/codegen-llvm/default-visibility.rs
+++ b/tests/codegen-llvm/default-visibility.rs
@@ -32,6 +32,7 @@ pub static tested_symbol: [u8; 6] = *b"foobar";
 // INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
 // DEFAULT:      @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
 
+#[inline(never)]
 pub fn do_memcmp(left: &[u8], right: &[u8]) -> i32 {
     left.cmp(right) as i32
 }
diff --git a/tests/codegen-llvm/gpu-kernel-abi.rs b/tests/codegen-llvm/gpu-kernel-abi.rs
index 8ac376d9338..d5a357ef655 100644
--- a/tests/codegen-llvm/gpu-kernel-abi.rs
+++ b/tests/codegen-llvm/gpu-kernel-abi.rs
@@ -1,7 +1,9 @@
 // Checks that the gpu-kernel calling convention correctly translates to LLVM calling conventions.
 
 //@ add-core-stubs
-//@ revisions: nvptx
+//@ revisions: amdgpu nvptx
+//@ [amdgpu] compile-flags: --crate-type=rlib --target=amdgcn-amd-amdhsa -Ctarget-cpu=gfx900
+//@ [amdgpu] needs-llvm-components: amdgpu
 //@ [nvptx] compile-flags: --crate-type=rlib --target=nvptx64-nvidia-cuda
 //@ [nvptx] needs-llvm-components: nvptx
 #![feature(no_core, lang_items, abi_gpu_kernel)]
@@ -10,6 +12,7 @@
 extern crate minicore;
 use minicore::*;
 
+// amdgpu: define amdgpu_kernel void @fun(i32
 // nvptx: define ptx_kernel void @fun(i32
 #[no_mangle]
 pub extern "gpu-kernel" fn fun(_: i32) {}
diff --git a/tests/codegen-llvm/loongarch-abi/cast-local-large-enough.rs b/tests/codegen-llvm/loongarch-abi/cast-local-large-enough.rs
new file mode 100644
index 00000000000..e5a0e4cd3a2
--- /dev/null
+++ b/tests/codegen-llvm/loongarch-abi/cast-local-large-enough.rs
@@ -0,0 +1,44 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target loongarch64-unknown-linux-gnu
+//@ needs-llvm-components: loongarch
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C, align(64))]
+struct Aligned(f64);
+
+#[repr(C, align(64))]
+struct AlignedPair(f32, f64);
+
+impl Copy for Aligned {}
+impl Copy for AlignedPair {}
+
+// CHECK-LABEL: define double @read_aligned
+#[unsafe(no_mangle)]
+pub extern "C" fn read_aligned(x: &Aligned) -> Aligned {
+    // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
+    // CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64
+    // CHECK-NEXT: ret double %[[RES]]
+    *x
+}
+
+// CHECK-LABEL: define { float, double } @read_aligned_pair
+#[unsafe(no_mangle)]
+pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair {
+    // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
+    // CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64
+    // CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8
+    // CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8
+    // CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0
+    // CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1
+    // CHECK-NEXT: ret { float, double } %[[RES2]]
+    *x
+}
diff --git a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
index 642bf5e7576..ada525b6c80 100644
--- a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
+++ b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
@@ -19,7 +19,7 @@
 //@ only-linux
 //
 //@ revisions:ASAN ASAN-FAT-LTO
-//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static
+//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 // [ASAN] no extra compile-flags
 //@[ASAN-FAT-LTO] compile-flags: -Cprefer-dynamic=false -Clto=fat
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs
index 22577e2a3c4..77857ca4ccb 100644
--- a/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs
@@ -1,7 +1,7 @@
 // Verifies that "CFI Canonical Jump Tables" module flag is added.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
index a54a6d84a80..6cf9a72b748 100644
--- a/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
@@ -1,7 +1,7 @@
 // Verifies that "cfi-normalize-integers" module flag is added.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs
index 283b8f26102..0bfdbfba5d2 100644
--- a/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs
@@ -1,7 +1,7 @@
 // Verifies that "EnableSplitLTOUnit" module flag is added.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs
index df65960dfe0..2a18e30e2b0 100644
--- a/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs
@@ -1,7 +1,7 @@
 // Verifies that the parent block's debug information are assigned to the inserted cfi block.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs
index 651afb33228..c49438f4318 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs
@@ -1,7 +1,7 @@
 // Verifies that pointer type membership tests for indirect calls are omitted.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 #![feature(sanitize)]
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs
index ebc66a015df..9cad88f6518 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs
@@ -1,7 +1,7 @@
 // Verifies that pointer type membership tests for indirect calls are emitted.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs
index 9bc2e42db0f..cd9088f58af 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs
@@ -1,7 +1,7 @@
 // Verifies that user-defined CFI encoding for types are emitted.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 #![feature(cfi_encoding, extern_types)]
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs
index 9048c6a1f18..cf26c17af1e 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs
@@ -2,7 +2,7 @@
 // for const generics.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 #![feature(type_alias_impl_trait)]
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
index 8fec275fd06..279350d20c5 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
@@ -5,7 +5,7 @@
 // future.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs
index 7e60aafff68..047b532e994 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs
@@ -2,7 +2,7 @@
 // for function types.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs
index 36d2e8c9f25..92b2ab32ea0 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs
@@ -2,7 +2,7 @@
 // for lifetimes/regions.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 #![feature(type_alias_impl_trait)]
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
index 9d611777ff0..5de39dc85c1 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
@@ -2,7 +2,7 @@
 // self so they can be used as function pointers.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
index a8ba8db1be3..f5846713bd5 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
@@ -2,7 +2,7 @@
 // for paths.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 #![feature(type_alias_impl_trait)]
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs
index d37bb740f55..ad4fe11d087 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs
@@ -2,7 +2,7 @@
 // for pointer types.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
index 7d9e4d05872..93845d05195 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
@@ -2,7 +2,7 @@
 // for primitive types.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
index 0f97c70f3f9..025aa902658 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
@@ -2,7 +2,7 @@
 // for repr transparent types.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs
index bdee3f47a83..76c8150b778 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs
@@ -2,7 +2,7 @@
 // for sequence types.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs
index 55e816178f8..4fafdd2f040 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs
@@ -2,7 +2,7 @@
 // for trait types.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs
index c1f3ca61afe..91351096ca2 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs
@@ -2,7 +2,7 @@
 // for user-defined types.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 #![feature(extern_types)]
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs
index 32637b64b3e..22d518cca74 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs
@@ -1,7 +1,7 @@
 // Verifies that generalized type metadata for functions are emitted.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
index 51121b0aef1..7639ce7b104 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
@@ -1,7 +1,7 @@
 // Verifies that normalized and generalized type metadata for functions are emitted.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs
index 1cfdd23006e..acd72b0ca3c 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs
@@ -1,7 +1,7 @@
 // Verifies that normalized type metadata for functions are emitted.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs
index 56ab1ce4b35..fa5cd471466 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs
@@ -1,7 +1,7 @@
 // Verifies that type metadata for functions are emitted.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs
index 0e57ce322d1..82873e935b2 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs
@@ -1,7 +1,7 @@
 // Verifies that type metadata identifiers for trait objects are emitted correctly.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs
index b3cb6dfdd37..893b0167693 100644
--- a/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs
@@ -2,7 +2,7 @@
 // emitted correctly.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 #![crate_type = "bin"]
 #![feature(linkage)]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs
index 57004da6f8e..caa2f258f8f 100644
--- a/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs
@@ -1,7 +1,7 @@
 // Verifies that pointer types are generalized.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs
index 770ee4e64e0..16f76adafb8 100644
--- a/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs
@@ -1,7 +1,7 @@
 // Verifies that integer types are normalized.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs
index a2d0d63cc17..cd8c2c48ea4 100644
--- a/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs
+++ b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs
@@ -1,7 +1,7 @@
 // Verifies that functions are instrumented.
 //
 //@ needs-sanitizer-dataflow
-//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow
+//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/memory-track-origins.rs b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
index 5eb5b356b05..a72e523c4e1 100644
--- a/tests/codegen-llvm/sanitizer/memory-track-origins.rs
+++ b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
@@ -4,7 +4,7 @@
 //@ needs-sanitizer-memory
 //@ revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO
 //
-//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static
+//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 // [MSAN-0] no extra compile-flags
 //@[MSAN-1] compile-flags: -Zsanitizer-memory-track-origins=1
 //@[MSAN-2] compile-flags: -Zsanitizer-memory-track-origins
diff --git a/tests/codegen-llvm/sanitizer/memtag-attr-check.rs b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs
index ffe3a2322a2..fc430f3a570 100644
--- a/tests/codegen-llvm/sanitizer/memtag-attr-check.rs
+++ b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs
@@ -2,7 +2,7 @@
 // applied when enabling the memtag sanitizer.
 //
 //@ needs-sanitizer-memtag
-//@ compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/safestack-attr-check.rs b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs
index 050a60333af..414dd89a580 100644
--- a/tests/codegen-llvm/sanitizer/safestack-attr-check.rs
+++ b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs
@@ -1,7 +1,7 @@
 // This tests that the safestack attribute is applied when enabling the safe-stack sanitizer.
 //
 //@ needs-sanitizer-safestack
-//@ compile-flags: -Zsanitizer=safestack -Copt-level=0
+//@ compile-flags: -Zsanitizer=safestack -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs b/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs
index 69771827c3a..0f43e6b8393 100644
--- a/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs
+++ b/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs
@@ -1,9 +1,9 @@
 // Verifies that sanitize(xyz = "off") attribute prevents inlining when
 // given sanitizer is enabled, but has no effect on inlining otherwise.
-//
 //@ needs-sanitizer-address
 //@ needs-sanitizer-leak
 //@ revisions: ASAN LSAN
+//@       compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
 //@       compile-flags: -Copt-level=3 -Zmir-opt-level=4 -Ctarget-feature=-crt-static
 //@[ASAN] compile-flags: -Zsanitizer=address
 //@[LSAN] compile-flags: -Zsanitizer=leak
diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs b/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs
index 94945f2b2e6..61ad0ba7d90 100644
--- a/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs
+++ b/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs
@@ -2,7 +2,7 @@
 // the address sanitizer.
 //
 //@ needs-sanitizer-address
-//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0
+//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer
 
 #![crate_type = "lib"]
 #![feature(sanitize)]
diff --git a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs
index 6b659320481..b8a24e31c30 100644
--- a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs
+++ b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs
@@ -5,7 +5,7 @@
 //@ needs-sanitizer-memory
 //@ revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO
 //@ no-prefer-dynamic
-//
+//@                   compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
 //@                   compile-flags: -Ctarget-feature=-crt-static
 //@[ASAN]             compile-flags: -Zsanitizer=address -Copt-level=0
 //@[ASAN-RECOVER]     compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0
diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
index 8afb6ad250e..a18d7e7478f 100644
--- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -1,30 +1,30 @@
 // MIR for `address_of_reborrow` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10]
+| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10]
 | 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send
-| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
-| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
 | 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
 | 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
 | 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
 | 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
 | 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
 | 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
-| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10]
+| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10]
 | 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send
-| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
-| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
 | 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
 | 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
 | 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
 | 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
 | 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
 | 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
-| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10]
+| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10]
 | 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send
-| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
-| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
 | 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
 | 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
 | 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
diff --git a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-abort.diff
index 5d8aaedae37..a2f10be31a9 100644
--- a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-abort.diff
@@ -8,25 +8,23 @@
       let _5: ();
       let mut _6: i32;
       scope 1 {
--         debug x => _1;
-+         debug x => _6;
+          debug x => _1;
           let _2: i32;
           scope 2 {
 -             debug y => _2;
-+             debug y => _6;
++             debug y => _1;
               let _3: i32;
               scope 3 {
 -                 debug z => _3;
-+                 debug z => _6;
++                 debug z => _1;
               }
           }
       }
   
       bb0: {
 -         StorageLive(_1);
--         _1 = val() -> [return: bb1, unwind unreachable];
 +         nop;
-+         _6 = val() -> [return: bb1, unwind unreachable];
+          _1 = val() -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -49,9 +47,10 @@
           StorageLive(_5);
 -         StorageLive(_6);
 -         _6 = copy _1;
+-         _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind unreachable];
 +         nop;
 +         nop;
-          _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind unreachable];
++         _5 = std::mem::drop::<i32>(move _1) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff
index 05c9bcc1d73..a08488615b1 100644
--- a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff
@@ -8,25 +8,23 @@
       let _5: ();
       let mut _6: i32;
       scope 1 {
--         debug x => _1;
-+         debug x => _6;
+          debug x => _1;
           let _2: i32;
           scope 2 {
 -             debug y => _2;
-+             debug y => _6;
++             debug y => _1;
               let _3: i32;
               scope 3 {
 -                 debug z => _3;
-+                 debug z => _6;
++                 debug z => _1;
               }
           }
       }
   
       bb0: {
 -         StorageLive(_1);
--         _1 = val() -> [return: bb1, unwind continue];
 +         nop;
-+         _6 = val() -> [return: bb1, unwind continue];
+          _1 = val() -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -49,9 +47,10 @@
           StorageLive(_5);
 -         StorageLive(_6);
 -         _6 = copy _1;
+-         _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind continue];
 +         nop;
 +         nop;
-          _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind continue];
++         _5 = std::mem::drop::<i32>(move _1) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-abort.mir b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-abort.mir
index eb4209731c6..15061da8120 100644
--- a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-abort.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-abort.mir
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
     let mut _3: usize;
     let mut _4: usize;
     scope 1 {
-        debug b => _3;
+        debug b => _2;
     }
 
     bb0: {
         nop;
-        _3 = copy _1;
+        _2 = copy _1;
         _1 = const 5_usize;
         nop;
         nop;
-        _1 = move _3;
+        _1 = move _2;
         nop;
         nop;
         nop;
diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir
index fe9a7376a58..ddfe4dc5b3e 100644
--- a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
     let mut _3: usize;
     let mut _4: usize;
     scope 1 {
-        debug b => _3;
+        debug b => _2;
     }
 
     bb0: {
         nop;
-        _3 = copy _1;
+        _2 = copy _1;
         _1 = const 5_usize;
         nop;
         nop;
-        _1 = move _3;
+        _1 = move _2;
         nop;
         nop;
         nop;
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir
index eb4209731c6..15061da8120 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
     let mut _3: usize;
     let mut _4: usize;
     scope 1 {
-        debug b => _3;
+        debug b => _2;
     }
 
     bb0: {
         nop;
-        _3 = copy _1;
+        _2 = copy _1;
         _1 = const 5_usize;
         nop;
         nop;
-        _1 = move _3;
+        _1 = move _2;
         nop;
         nop;
         nop;
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
index fe9a7376a58..ddfe4dc5b3e 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
     let mut _3: usize;
     let mut _4: usize;
     scope 1 {
-        debug b => _3;
+        debug b => _2;
     }
 
     bb0: {
         nop;
-        _3 = copy _1;
+        _2 = copy _1;
         _1 = const 5_usize;
         nop;
         nop;
-        _1 = move _3;
+        _1 = move _2;
         nop;
         nop;
         nop;
diff --git a/tests/mir-opt/gvn_overlapping.fields.GVN.diff b/tests/mir-opt/gvn_overlapping.fields.GVN.diff
new file mode 100644
index 00000000000..0548f4e42e4
--- /dev/null
+++ b/tests/mir-opt/gvn_overlapping.fields.GVN.diff
@@ -0,0 +1,14 @@
+- // MIR for `fields` before GVN
++ // MIR for `fields` after GVN
+  
+  fn fields(_1: (Adt, Adt)) -> () {
+      let mut _0: ();
+      let mut _2: u32;
+  
+      bb0: {
+          _2 = copy (((_1.0: Adt) as variant#1).0: u32);
+          (_1.1: Adt) = Adt::Some(copy _2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn_overlapping.rs b/tests/mir-opt/gvn_overlapping.rs
index 99113445e68..f148a843561 100644
--- a/tests/mir-opt/gvn_overlapping.rs
+++ b/tests/mir-opt/gvn_overlapping.rs
@@ -2,11 +2,10 @@
 
 #![feature(custom_mir, core_intrinsics)]
 
-// Check that we do not create overlapping assignments.
-
 use std::intrinsics::mir::*;
 
 // EMIT_MIR gvn_overlapping.overlapping.GVN.diff
+/// Check that we do not create overlapping assignments.
 #[custom_mir(dialect = "runtime")]
 fn overlapping(_17: Adt) {
     // CHECK-LABEL: fn overlapping(
@@ -26,6 +25,45 @@ fn overlapping(_17: Adt) {
     }
 }
 
+// EMIT_MIR gvn_overlapping.stable_projection.GVN.diff
+/// Check that we allow dereferences in the RHS if the LHS is a stable projection.
+#[custom_mir(dialect = "runtime")]
+fn stable_projection(_1: (Adt,)) {
+    // CHECK-LABEL: fn stable_projection(
+    // CHECK: let mut _2: *mut Adt;
+    // CHECK: let mut _4: &Adt;
+    // CHECK: (_1.0: Adt) = copy (*_4);
+    mir! {
+        let _2: *mut Adt;
+        let _3: u32;
+        let _4: &Adt;
+        {
+            _2 = core::ptr::addr_of_mut!(_1.0);
+            _4 = &(*_2);
+            _3 = Field(Variant((*_4), 1), 0);
+            _1.0 = Adt::Some(_3);
+            Return()
+        }
+    }
+}
+
+// EMIT_MIR gvn_overlapping.fields.GVN.diff
+/// Check that we do not create assignments between different fields of the same local.
+#[custom_mir(dialect = "runtime")]
+fn fields(_1: (Adt, Adt)) {
+    // CHECK-LABEL: fn fields(
+    // CHECK: _2 = copy (((_1.0: Adt) as variant#1).0: u32);
+    // CHECK-NEXT: (_1.1: Adt) = Adt::Some(copy _2);
+    mir! {
+        let _2: u32;
+        {
+            _2 = Field(Variant(_1.0, 1), 0);
+            _1.1 = Adt::Some(_2);
+            Return()
+        }
+    }
+}
+
 fn main() {
     overlapping(Adt::Some(0));
 }
diff --git a/tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff b/tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff
new file mode 100644
index 00000000000..08835456591
--- /dev/null
+++ b/tests/mir-opt/gvn_overlapping.stable_projection.GVN.diff
@@ -0,0 +1,19 @@
+- // MIR for `stable_projection` before GVN
++ // MIR for `stable_projection` after GVN
+  
+  fn stable_projection(_1: (Adt,)) -> () {
+      let mut _0: ();
+      let mut _2: *mut Adt;
+      let mut _3: u32;
+      let mut _4: &Adt;
+  
+      bb0: {
+          _2 = &raw mut (_1.0: Adt);
+          _4 = &(*_2);
+          _3 = copy (((*_4) as variant#1).0: u32);
+-         (_1.0: Adt) = Adt::Some(copy _3);
++         (_1.0: Adt) = copy (*_4);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/nrvo_miscompile_111005.rs b/tests/mir-opt/nrvo_miscompile_111005.rs
index 03008fa8191..131f7b8f6f9 100644
--- a/tests/mir-opt/nrvo_miscompile_111005.rs
+++ b/tests/mir-opt/nrvo_miscompile_111005.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // This is a miscompilation, #111005 to track
 
 //@ test-mir-pass: RenameReturnPlace
@@ -10,6 +9,11 @@ use core::intrinsics::mir::*;
 // EMIT_MIR nrvo_miscompile_111005.wrong.RenameReturnPlace.diff
 #[custom_mir(dialect = "runtime", phase = "initial")]
 pub fn wrong(arg: char) -> char {
+    // CHECK-LABEL: fn wrong(
+    // CHECK: _0 = copy _1;
+    // FIXME: This is wrong:
+    // CHECK-NEXT: _0 = const 'b';
+    // CHECK-NEXT: return;
     mir! {
         {
             let temp = arg;
diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir
index 9f88e1961ec..e67f362ee04 100644
--- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir
@@ -6,8 +6,8 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 {
     scope 1 (inlined <Enum1 as Clone>::clone) {
         debug self => _1;
         let mut _2: isize;
-        let mut _3: &AllCopy;
-        let mut _4: &NestCopy;
+        let _3: &AllCopy;
+        let _4: &NestCopy;
         scope 2 {
             debug __self_0 => _3;
             scope 6 (inlined <AllCopy as Clone>::clone) {
diff --git a/tests/run-make/apple-slow-tls/rmake.rs b/tests/run-make-cargo/apple-slow-tls/rmake.rs
index 231e0b1668e..231e0b1668e 100644
--- a/tests/run-make/apple-slow-tls/rmake.rs
+++ b/tests/run-make-cargo/apple-slow-tls/rmake.rs
diff --git a/tests/run-make/apple-slow-tls/tls_test/Cargo.toml b/tests/run-make-cargo/apple-slow-tls/tls_test/Cargo.toml
index c8e5a228eef..c8e5a228eef 100644
--- a/tests/run-make/apple-slow-tls/tls_test/Cargo.toml
+++ b/tests/run-make-cargo/apple-slow-tls/tls_test/Cargo.toml
diff --git a/tests/run-make/apple-slow-tls/tls_test/src/main.rs b/tests/run-make-cargo/apple-slow-tls/tls_test/src/main.rs
index d48d22bb3d1..d48d22bb3d1 100644
--- a/tests/run-make/apple-slow-tls/tls_test/src/main.rs
+++ b/tests/run-make-cargo/apple-slow-tls/tls_test/src/main.rs
diff --git a/tests/run-make/compiler-builtins/Cargo.toml b/tests/run-make-cargo/compiler-builtins/Cargo.toml
index 869210c4a68..869210c4a68 100644
--- a/tests/run-make/compiler-builtins/Cargo.toml
+++ b/tests/run-make-cargo/compiler-builtins/Cargo.toml
diff --git a/tests/run-make/compiler-builtins/lib.rs b/tests/run-make-cargo/compiler-builtins/lib.rs
index 0c9ac1ac8e4..0c9ac1ac8e4 100644
--- a/tests/run-make/compiler-builtins/lib.rs
+++ b/tests/run-make-cargo/compiler-builtins/lib.rs
diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make-cargo/compiler-builtins/rmake.rs
index 10093db2258..10093db2258 100644
--- a/tests/run-make/compiler-builtins/rmake.rs
+++ b/tests/run-make-cargo/compiler-builtins/rmake.rs
diff --git a/tests/run-make/rustc-crates-on-stable/rmake.rs b/tests/run-make-cargo/rustc-crates-on-stable/rmake.rs
index cbc1f24b8c1..cbc1f24b8c1 100644
--- a/tests/run-make/rustc-crates-on-stable/rmake.rs
+++ b/tests/run-make-cargo/rustc-crates-on-stable/rmake.rs
diff --git a/tests/run-make/rustdoc-scrape-examples-paths/foo/Cargo.toml b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/Cargo.toml
index 6962028375b..6962028375b 100644
--- a/tests/run-make/rustdoc-scrape-examples-paths/foo/Cargo.toml
+++ b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/Cargo.toml
diff --git a/tests/run-make/rustdoc-scrape-examples-paths/foo/examples/complex.rs b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/examples/complex.rs
index 1cda7e098f4..1cda7e098f4 100644
--- a/tests/run-make/rustdoc-scrape-examples-paths/foo/examples/complex.rs
+++ b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/examples/complex.rs
diff --git a/tests/run-make/rustdoc-scrape-examples-paths/foo/examples/tester.rs b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/examples/tester.rs
index fbd1906ec09..fbd1906ec09 100644
--- a/tests/run-make/rustdoc-scrape-examples-paths/foo/examples/tester.rs
+++ b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/examples/tester.rs
diff --git a/tests/run-make/rustdoc-scrape-examples-paths/foo/src/lib.rs b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/src/lib.rs
index a9bb0272c78..a9bb0272c78 100644
--- a/tests/run-make/rustdoc-scrape-examples-paths/foo/src/lib.rs
+++ b/tests/run-make-cargo/rustdoc-scrape-examples-paths/foo/src/lib.rs
diff --git a/tests/run-make/rustdoc-scrape-examples-paths/rmake.rs b/tests/run-make-cargo/rustdoc-scrape-examples-paths/rmake.rs
index 6784e438762..6784e438762 100644
--- a/tests/run-make/rustdoc-scrape-examples-paths/rmake.rs
+++ b/tests/run-make-cargo/rustdoc-scrape-examples-paths/rmake.rs
diff --git a/tests/run-make/thumb-none-cortex-m/rmake.rs b/tests/run-make-cargo/thumb-none-cortex-m/rmake.rs
index 27afef874da..6158b9c36da 100644
--- a/tests/run-make/thumb-none-cortex-m/rmake.rs
+++ b/tests/run-make-cargo/thumb-none-cortex-m/rmake.rs
@@ -4,7 +4,7 @@
 //!
 //! How to run this
 //! $ ./x.py clean
-//! $ ./x.py test --target thumbv6m-none-eabi,thumbv7m-none-eabi tests/run-make
+//! $ ./x.py test --target thumbv6m-none-eabi,thumbv7m-none-eabi tests/run-make-cargo
 //!
 //! Supported targets:
 //! - thumbv6m-none-eabi (Bare Cortex-M0, M0+, M1)
diff --git a/tests/run-make/thumb-none-qemu/example/.cargo/config.toml b/tests/run-make-cargo/thumb-none-qemu/example/.cargo/config.toml
index 7152e81b502..7152e81b502 100644
--- a/tests/run-make/thumb-none-qemu/example/.cargo/config.toml
+++ b/tests/run-make-cargo/thumb-none-qemu/example/.cargo/config.toml
diff --git a/tests/run-make/thumb-none-qemu/example/Cargo.lock b/tests/run-make-cargo/thumb-none-qemu/example/Cargo.lock
index 687b962a8b6..687b962a8b6 100644
--- a/tests/run-make/thumb-none-qemu/example/Cargo.lock
+++ b/tests/run-make-cargo/thumb-none-qemu/example/Cargo.lock
diff --git a/tests/run-make/thumb-none-qemu/example/Cargo.toml b/tests/run-make-cargo/thumb-none-qemu/example/Cargo.toml
index 63eb5f90aec..63eb5f90aec 100644
--- a/tests/run-make/thumb-none-qemu/example/Cargo.toml
+++ b/tests/run-make-cargo/thumb-none-qemu/example/Cargo.toml
diff --git a/tests/run-make/thumb-none-qemu/example/memory.x b/tests/run-make-cargo/thumb-none-qemu/example/memory.x
index dc7ad967a42..dc7ad967a42 100644
--- a/tests/run-make/thumb-none-qemu/example/memory.x
+++ b/tests/run-make-cargo/thumb-none-qemu/example/memory.x
diff --git a/tests/run-make/thumb-none-qemu/example/src/main.rs b/tests/run-make-cargo/thumb-none-qemu/example/src/main.rs
index 4b8162c4120..4b8162c4120 100644
--- a/tests/run-make/thumb-none-qemu/example/src/main.rs
+++ b/tests/run-make-cargo/thumb-none-qemu/example/src/main.rs
diff --git a/tests/run-make/thumb-none-qemu/rmake.rs b/tests/run-make-cargo/thumb-none-qemu/rmake.rs
index 9d4b426f4a1..9d4b426f4a1 100644
--- a/tests/run-make/thumb-none-qemu/rmake.rs
+++ b/tests/run-make-cargo/thumb-none-qemu/rmake.rs
diff --git a/tests/run-make/uefi-qemu/rmake.rs b/tests/run-make-cargo/uefi-qemu/rmake.rs
index 55d42fba5e7..55d42fba5e7 100644
--- a/tests/run-make/uefi-qemu/rmake.rs
+++ b/tests/run-make-cargo/uefi-qemu/rmake.rs
diff --git a/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.lock b/tests/run-make-cargo/uefi-qemu/uefi_qemu_test/Cargo.lock
index 8b6a664ad93..8b6a664ad93 100644
--- a/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.lock
+++ b/tests/run-make-cargo/uefi-qemu/uefi_qemu_test/Cargo.lock
diff --git a/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.toml b/tests/run-make-cargo/uefi-qemu/uefi_qemu_test/Cargo.toml
index 1a8d0d94368..1a8d0d94368 100644
--- a/tests/run-make/uefi-qemu/uefi_qemu_test/Cargo.toml
+++ b/tests/run-make-cargo/uefi-qemu/uefi_qemu_test/Cargo.toml
diff --git a/tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs b/tests/run-make-cargo/uefi-qemu/uefi_qemu_test/src/main.rs
index f8e1212a9f6..f8e1212a9f6 100644
--- a/tests/run-make/uefi-qemu/uefi_qemu_test/src/main.rs
+++ b/tests/run-make-cargo/uefi-qemu/uefi_qemu_test/src/main.rs
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks
index d2e53bee08f..d2e53bee08f 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks
index b93b33afb3f..b93b33afb3f 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks
index 0a3d1dced42..0a3d1dced42 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks
index f96f152c02f..f96f152c02f 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks
index 0126cd8ee64..0126cd8ee64 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks
index 61567548848..61567548848 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks
index f551356b2ff..f551356b2ff 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks
index 17312b9126a..17312b9126a 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks
index 4b66cc5bc83..4b66cc5bc83 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks
index 0f403e0203c..0f403e0203c 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks
index 222e4ef7983..222e4ef7983 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks
index 1d8fc96ad50..1d8fc96ad50 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml
index 3a97c37e951..3a97c37e951 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs
index f1fb5803948..f1fb5803948 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c
index dd76d4f303a..dd76d4f303a 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s
index 6d56214e87e..6d56214e87e 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp
index ac6f64ac413..ac6f64ac413 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt
index 27cdf2ecf82..27cdf2ecf82 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c
index c3b731a2d50..c3b731a2d50 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s
index 64b6b430eea..64b6b430eea 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp
index 824e2afebcc..824e2afebcc 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs
index cde38aacf7f..cde38aacf7f 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks
index 885bf461bf3..885bf461bf3 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.with_frame_pointers.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/print.with_frame_pointers.checks
index 485e20e3111..485e20e3111 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.with_frame_pointers.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/print.with_frame_pointers.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.without_frame_pointers.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/print.without_frame_pointers.checks
index e02fe094889..e02fe094889 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.without_frame_pointers.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/print.without_frame_pointers.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
index 89754cdaf90..89754cdaf90 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks
index fe6777537fb..fe6777537fb 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks
index b46cf758384..b46cf758384 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks
+++ b/tests/run-make-cargo/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks
diff --git a/tests/run-make/apple-c-available-links/foo.c b/tests/run-make/apple-c-available-links/foo.c
new file mode 100644
index 00000000000..eff99a8b12a
--- /dev/null
+++ b/tests/run-make/apple-c-available-links/foo.c
@@ -0,0 +1,22 @@
+int foo(void) {
+    // Act as if using some API that's a lot newer than the deployment target.
+    //
+    // This forces Clang to insert a call to __isPlatformVersionAtLeast,
+    // and linking will fail if that is not present.
+    if (__builtin_available(
+        macos 1000.0,
+        ios 1000.0,
+        tvos 1000.0,
+        watchos 1000.0,
+        // CI runs below Xcode 15, where `visionos` wasn't a valid key in
+        // `__builtin_available`.
+#ifdef TARGET_OS_VISION
+        visionos 1000.0,
+#endif
+        *
+    )) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
diff --git a/tests/run-make/apple-c-available-links/main.rs b/tests/run-make/apple-c-available-links/main.rs
new file mode 100644
index 00000000000..4ffada43c1b
--- /dev/null
+++ b/tests/run-make/apple-c-available-links/main.rs
@@ -0,0 +1,7 @@
+unsafe extern "C" {
+    safe fn foo() -> core::ffi::c_int;
+}
+
+fn main() {
+    assert_eq!(foo(), 0);
+}
diff --git a/tests/run-make/apple-c-available-links/rmake.rs b/tests/run-make/apple-c-available-links/rmake.rs
new file mode 100644
index 00000000000..44a5ee94d57
--- /dev/null
+++ b/tests/run-make/apple-c-available-links/rmake.rs
@@ -0,0 +1,14 @@
+//! Test that using `__builtin_available` in C (`@available` in Objective-C)
+//! successfully links (because `std` provides the required symbols).
+
+//@ only-apple __builtin_available is (mostly) specific to Apple platforms.
+
+use run_make_support::{cc, rustc, target};
+
+fn main() {
+    // Invoke the C compiler to generate an object file.
+    cc().arg("-c").input("foo.c").output("foo.o").run();
+
+    // Link the object file together with a Rust program.
+    rustc().target(target()).input("main.rs").link_arg("foo.o").run();
+}
diff --git a/tests/run-make/multiline-args-value/cfg-frontmatter.stderr b/tests/run-make/multiline-args-value/cfg-frontmatter.stderr
new file mode 100644
index 00000000000..9b06f84be48
--- /dev/null
+++ b/tests/run-make/multiline-args-value/cfg-frontmatter.stderr
@@ -0,0 +1,4 @@
+error: invalid `--cfg` argument: `---
+       ---
+       key` (expected `key` or `key="value"`)
+
diff --git a/tests/run-make/multiline-args-value/cfg-shebang.stderr b/tests/run-make/multiline-args-value/cfg-shebang.stderr
new file mode 100644
index 00000000000..09baf3b5123
--- /dev/null
+++ b/tests/run-make/multiline-args-value/cfg-shebang.stderr
@@ -0,0 +1,3 @@
+error: invalid `--cfg` argument: `#!/usr/bin/shebang
+       key` (expected `key` or `key="value"`)
+
diff --git a/tests/run-make/multiline-args-value/check-cfg-frontmatter.stderr b/tests/run-make/multiline-args-value/check-cfg-frontmatter.stderr
new file mode 100644
index 00000000000..4a499cc0a1e
--- /dev/null
+++ b/tests/run-make/multiline-args-value/check-cfg-frontmatter.stderr
@@ -0,0 +1,7 @@
+error: invalid `--check-cfg` argument: `---
+       ---
+       cfg(key)`
+  |
+  = note: expected `cfg(name, values("value1", "value2", ... "valueN"))`
+  = note: visit <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more details
+
diff --git a/tests/run-make/multiline-args-value/check-cfg-shebang.stderr b/tests/run-make/multiline-args-value/check-cfg-shebang.stderr
new file mode 100644
index 00000000000..5bf18dc2b14
--- /dev/null
+++ b/tests/run-make/multiline-args-value/check-cfg-shebang.stderr
@@ -0,0 +1,6 @@
+error: invalid `--check-cfg` argument: `#!/usr/bin/shebang
+       cfg(key)`
+  |
+  = note: expected `cfg(name, values("value1", "value2", ... "valueN"))`
+  = note: visit <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more details
+
diff --git a/tests/run-make/multiline-args-value/rmake.rs b/tests/run-make/multiline-args-value/rmake.rs
new file mode 100644
index 00000000000..3964cbbc1e6
--- /dev/null
+++ b/tests/run-make/multiline-args-value/rmake.rs
@@ -0,0 +1,51 @@
+use run_make_support::{cwd, diff, rustc};
+
+fn test_and_compare(test_name: &str, flag: &str, val: &str) {
+    let mut cmd = rustc();
+
+    let output = cmd.input("").arg("--crate-type=lib").arg(flag).arg(val).run_fail();
+
+    assert_eq!(output.stdout_utf8(), "");
+    diff()
+        .expected_file(format!("{test_name}.stderr"))
+        .actual_text("stderr", output.stderr_utf8())
+        .run();
+}
+
+fn main() {
+    // Verify that frontmatter isn't allowed in `--cfg` arguments.
+    // https://github.com/rust-lang/rust/issues/146130
+    test_and_compare(
+        "cfg-frontmatter",
+        "--cfg",
+        r#"---
+---
+key"#,
+    );
+
+    // Verify that frontmatter isn't allowed in `--check-cfg` arguments.
+    // https://github.com/rust-lang/rust/issues/146130
+    test_and_compare(
+        "check-cfg-frontmatter",
+        "--check-cfg",
+        r#"---
+---
+cfg(key)"#,
+    );
+
+    // Verify that shebang isn't allowed in `--cfg` arguments.
+    test_and_compare(
+        "cfg-shebang",
+        "--cfg",
+        r#"#!/usr/bin/shebang
+key"#,
+    );
+
+    // Verify that shebang isn't allowed in `--check-cfg` arguments.
+    test_and_compare(
+        "check-cfg-shebang",
+        "--check-cfg",
+        r#"#!/usr/bin/shebang
+cfg(key)"#,
+    );
+}
diff --git a/tests/run-make/rustdoc-dep-info/rmake.rs b/tests/run-make/rustdoc-dep-info/rmake.rs
index 625f81fd428..166e8d5702f 100644
--- a/tests/run-make/rustdoc-dep-info/rmake.rs
+++ b/tests/run-make/rustdoc-dep-info/rmake.rs
@@ -33,4 +33,16 @@ fn main() {
     // Now we check that we can provide a file name to the `dep-info` argument.
     rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info=bla.d").run();
     assert!(path("bla.d").exists());
+
+    // The last emit-type wins. The same behavior as rustc.
+    rustdoc()
+        .input("lib.rs")
+        .arg("-Zunstable-options")
+        .emit("dep-info=precedence1.d")
+        .emit("dep-info=precedence2.d")
+        .emit("dep-info=precedence3.d")
+        .run();
+    assert!(!path("precedence1.d").exists());
+    assert!(!path("precedence2.d").exists());
+    assert!(path("precedence3.d").exists());
 }
diff --git a/tests/run-make/rustdoc-search-load-itemtype/bar.rs b/tests/run-make/rustdoc-search-load-itemtype/bar.rs
new file mode 100644
index 00000000000..0416b1b75b5
--- /dev/null
+++ b/tests/run-make/rustdoc-search-load-itemtype/bar.rs
@@ -0,0 +1,27 @@
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+//@ has bar/macro.a_procmacro.html
+//@ hasraw search.index/name/*.js a_procmacro
+#[proc_macro]
+pub fn a_procmacro(_: TokenStream) -> TokenStream {
+    unimplemented!()
+}
+
+//@ has bar/attr.a_procattribute.html
+//@ hasraw search.index/name/*.js a_procattribute
+#[proc_macro_attribute]
+pub fn a_procattribute(_: TokenStream, _: TokenStream) -> TokenStream {
+    unimplemented!()
+}
+
+//@ has bar/derive.AProcDerive.html
+//@ !has bar/derive.a_procderive.html
+//@ hasraw search.index/name/*.js AProcDerive
+//@ !hasraw search.index/name/*.js a_procderive
+#[proc_macro_derive(AProcDerive)]
+pub fn a_procderive(_: TokenStream) -> TokenStream {
+    unimplemented!()
+}
diff --git a/tests/run-make/rustdoc-search-load-itemtype/baz.rs b/tests/run-make/rustdoc-search-load-itemtype/baz.rs
new file mode 100644
index 00000000000..4d1f5430fc6
--- /dev/null
+++ b/tests/run-make/rustdoc-search-load-itemtype/baz.rs
@@ -0,0 +1,3 @@
+//@ has baz/struct.Baz.html
+//@ hasraw search.index/name/*.js Baz
+pub struct Baz;
diff --git a/tests/run-make/rustdoc-search-load-itemtype/foo.rs b/tests/run-make/rustdoc-search-load-itemtype/foo.rs
new file mode 100644
index 00000000000..93b372d10cb
--- /dev/null
+++ b/tests/run-make/rustdoc-search-load-itemtype/foo.rs
@@ -0,0 +1,119 @@
+#![feature(extern_types, rustc_attrs, rustdoc_internals, trait_alias)]
+#![allow(internal_features)]
+#![no_std]
+
+//@ has foo/keyword.while.html
+//@ hasraw search.index/name/*.js while
+//@ !hasraw search.index/name/*.js w_keyword
+#[doc(keyword = "while")]
+mod w_keyword {}
+
+//@ has foo/primitive.u32.html
+//@ hasraw search.index/name/*.js u32
+//@ !hasraw search.index/name/*.js u_primitive
+#[rustc_doc_primitive = "u32"]
+mod u_primitive {}
+
+//@ has foo/x_mod/index.html
+//@ hasraw search.index/name/*.js x_mod
+pub mod x_mod {}
+
+//@ hasraw foo/index.html y_crate
+//@ hasraw search.index/name/*.js y_crate
+#[doc(no_inline)]
+pub extern crate core as y_crate;
+
+//@ hasraw foo/index.html z_import
+//@ hasraw search.index/name/*.js z_import
+#[doc(no_inline)]
+pub use core::option as z_import;
+
+//@ has foo/struct.AStruct.html
+//@ hasraw search.index/name/*.js AStruct
+pub struct AStruct {
+    //@ hasraw foo/struct.AStruct.html a_structfield
+    //@ hasraw search.index/name/*.js a_structfield
+    pub a_structfield: i32,
+}
+
+//@ has foo/enum.AEnum.html
+//@ hasraw search.index/name/*.js AEnum
+pub enum AEnum {
+    //@ hasraw foo/enum.AEnum.html AVariant
+    //@ hasraw search.index/name/*.js AVariant
+    AVariant,
+}
+
+//@ has foo/fn.a_fn.html
+//@ hasraw search.index/name/*.js a_fn
+pub fn a_fn() {}
+
+//@ has foo/type.AType.html
+//@ hasraw search.index/name/*.js AType
+pub type AType = AStruct;
+
+//@ has foo/static.a_static.html
+//@ hasraw search.index/name/*.js a_static
+pub static a_static: i32 = 1;
+
+//@ has foo/trait.ATrait.html
+//@ hasraw search.index/name/*.js ATrait
+pub trait ATrait {
+    //@ hasraw foo/trait.ATrait.html a_tymethod
+    //@ hasraw search.index/name/*.js a_tymethod
+    fn a_tymethod();
+    //@ hasraw foo/trait.ATrait.html AAssocType
+    //@ hasraw search.index/name/*.js AAssocType
+    type AAssocType;
+    //@ hasraw foo/trait.ATrait.html AAssocConst
+    //@ hasraw search.index/name/*.js AAssocConst
+    const AAssocConst: bool;
+}
+
+// skip ItemType::Impl, since impls are anonymous
+// and have no search entry
+
+impl AStruct {
+    //@ hasraw foo/struct.AStruct.html a_method
+    //@ hasraw search.index/name/*.js a_method
+    pub fn a_method() {}
+}
+
+//@ has foo/macro.a_macro.html
+//@ hasraw search.index/name/*.js a_macro
+#[macro_export]
+macro_rules! a_macro {
+    () => {};
+}
+
+//@ has foo/constant.A_CONSTANT.html
+//@ hasraw search.index/name/*.js A_CONSTANT
+pub const A_CONSTANT: i32 = 1;
+
+//@ has foo/union.AUnion.html
+//@ hasraw search.index/name/*.js AUnion
+pub union AUnion {
+    //@ hasraw foo/union.AUnion.html a_unionfield
+    //@ hasraw search.index/name/*.js a_unionfield
+    pub a_unionfield: i32,
+}
+
+extern "C" {
+    //@ has foo/foreigntype.AForeignType.html
+    //@ hasraw search.index/name/*.js AForeignType
+    pub type AForeignType;
+}
+
+// procattribute and procderive are defined in
+// bar.rs, because they only work with proc_macro
+// crate type.
+
+//@ has foo/traitalias.ATraitAlias.html
+//@ hasraw search.index/name/*.js ATraitAlias
+pub trait ATraitAlias = ATrait;
+
+//@ has foo/attribute.doc.html
+//@ hasraw search.index/name/*.js doc
+//@ !hasraw search.index/name/*.js aa_mod
+#[doc(attribute = "doc")]
+mod aa_mod {}
diff --git a/tests/run-make/rustdoc-search-load-itemtype/rmake.rs b/tests/run-make/rustdoc-search-load-itemtype/rmake.rs
new file mode 100644
index 00000000000..803eb8a61da
--- /dev/null
+++ b/tests/run-make/rustdoc-search-load-itemtype/rmake.rs
@@ -0,0 +1,21 @@
+//@ ignore-cross-compile
+//@ needs-crate-type: proc-macro
+
+// Test that rustdoc can deserialize a search index with every itemtype.
+// https://github.com/rust-lang/rust/pull/146117
+
+use std::path::Path;
+
+use run_make_support::{htmldocck, rfs, rustdoc, source_root};
+
+fn main() {
+    let out_dir = Path::new("rustdoc-search-load-itemtype");
+
+    rfs::create_dir_all(&out_dir);
+    rustdoc().out_dir(&out_dir).input("foo.rs").run();
+    rustdoc().out_dir(&out_dir).input("bar.rs").arg("--crate-type=proc-macro").run();
+    rustdoc().out_dir(&out_dir).input("baz.rs").run();
+    htmldocck().arg(out_dir).arg("foo.rs").run();
+    htmldocck().arg(out_dir).arg("bar.rs").run();
+    htmldocck().arg(out_dir).arg("baz.rs").run();
+}
diff --git a/tests/run-make/sanitizer-cdylib-link/rmake.rs b/tests/run-make/sanitizer-cdylib-link/rmake.rs
index f9d7fd98789..8ff58594d10 100644
--- a/tests/run-make/sanitizer-cdylib-link/rmake.rs
+++ b/tests/run-make/sanitizer-cdylib-link/rmake.rs
@@ -8,6 +8,8 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-address
 
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+
 use run_make_support::{run_fail, rustc};
 
 fn main() {
diff --git a/tests/run-make/sanitizer-dylib-link/rmake.rs b/tests/run-make/sanitizer-dylib-link/rmake.rs
index b43420adc72..bae3240a236 100644
--- a/tests/run-make/sanitizer-dylib-link/rmake.rs
+++ b/tests/run-make/sanitizer-dylib-link/rmake.rs
@@ -7,6 +7,8 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-address
 
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+
 use run_make_support::{run_fail, rustc};
 
 fn main() {
diff --git a/tests/run-make/sanitizer-staticlib-link/rmake.rs b/tests/run-make/sanitizer-staticlib-link/rmake.rs
index e38d15a8a3c..dda92626189 100644
--- a/tests/run-make/sanitizer-staticlib-link/rmake.rs
+++ b/tests/run-make/sanitizer-staticlib-link/rmake.rs
@@ -11,6 +11,8 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-address
 
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+
 use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run_fail, rustc, static_lib_name};
 
 fn main() {
diff --git a/tests/run-make/separate-link-fail/rmake.rs b/tests/run-make/separate-link-fail/rmake.rs
index b5d5300de68..ba24f777395 100644
--- a/tests/run-make/separate-link-fail/rmake.rs
+++ b/tests/run-make/separate-link-fail/rmake.rs
@@ -11,5 +11,5 @@ fn main() {
         .arg("-Zlink-only")
         .input("foo.rs")
         .run_fail()
-        .assert_stderr_contains("The input does not look like a .rlink file");
+        .assert_stderr_contains("the input does not look like a .rlink file");
 }
diff --git a/tests/rustdoc-gui/scrape-examples-ice-links.goml b/tests/rustdoc-gui/scrape-examples-ice-links.goml
index 1db220e1a32..0a159621935 100644
--- a/tests/rustdoc-gui/scrape-examples-ice-links.goml
+++ b/tests/rustdoc-gui/scrape-examples-ice-links.goml
@@ -4,3 +4,5 @@ wait-for: ".scraped-example-title"
 assert-attribute: (".scraped-example-title a", {"href": "../src/bar/bar.rs.html#2"})
 click: ".scraped-example-title a"
 wait-for-property: ("h1", {"innerText": "bar/\nbar.rs"})
+// Ensure that the `--html-after-content` option was correctly handled.
+assert: "#outer-html"
diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/empty.html b/tests/rustdoc-gui/src/scrape_examples_ice/empty.html
deleted file mode 100644
index 8b137891791..00000000000
--- a/tests/rustdoc-gui/src/scrape_examples_ice/empty.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/extra.html b/tests/rustdoc-gui/src/scrape_examples_ice/extra.html
new file mode 100644
index 00000000000..e7a420154a6
--- /dev/null
+++ b/tests/rustdoc-gui/src/scrape_examples_ice/extra.html
@@ -0,0 +1 @@
+<span id="outer-html"></span>
diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs b/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs
index b854c7722c9..7d910c6de7d 100644
--- a/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs
+++ b/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs
@@ -1,5 +1,5 @@
 //@ run-flags:-Zrustdoc-scrape-examples
-//@ compile-flags: --html-after-content empty.html
+//@ compile-flags: --html-after-content extra.html
 pub struct ObscurelyNamedType1;
 
 impl ObscurelyNamedType1 {
diff --git a/tests/rustdoc/sanitizer-option.rs b/tests/rustdoc/sanitizer-option.rs
index 2adf1be51fd..7b0038138f0 100644
--- a/tests/rustdoc/sanitizer-option.rs
+++ b/tests/rustdoc/sanitizer-option.rs
@@ -1,6 +1,6 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-address
-//@ compile-flags: --test -Z sanitizer=address
+//@ compile-flags: --test -Z sanitizer=address -C unsafe-allow-abi-mismatch=sanitizer
 //
 // #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern
 // function that is provided by the sanitizer runtime, if flag is not passed
diff --git a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs
index b7636d116ec..aef25d057d4 100644
--- a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs
+++ b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs
@@ -1,5 +1,7 @@
 //@ revisions: emit_mir instrument cfi
 
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+
 // Make sure we don't try to emit MIR for it.
 //@[emit_mir] compile-flags: --emit=mir
 
diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr
index 675dfd335c4..b58016b5a81 100644
--- a/tests/ui/c-variadic/issue-86053-1.stderr
+++ b/tests/ui/c-variadic/issue-86053-1.stderr
@@ -47,10 +47,10 @@ LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize
    |            ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/issue-86053-1.rs:11:12
+  --> $DIR/issue-86053-1.rs:11:36
    |
 LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
-   |            ^^^                     ^^^
+   |                                    ^^^
 
 error[E0412]: cannot find type `F` in this scope
   --> $DIR/issue-86053-1.rs:11:48
diff --git a/tests/ui/c-variadic/no-closure.rs b/tests/ui/c-variadic/no-closure.rs
new file mode 100644
index 00000000000..c0b77786e8b
--- /dev/null
+++ b/tests/ui/c-variadic/no-closure.rs
@@ -0,0 +1,17 @@
+#![feature(c_variadic)]
+#![crate_type = "lib"]
+
+// Check that `...` in closures is rejected.
+
+const F: extern "C" fn(...) = |_: ...| {};
+//~^ ERROR C-variadic type `...` may not be nested inside another type
+
+fn foo() {
+    let f = |...| {};
+    //~^ ERROR: `..` patterns are not allowed here
+    //~| ERROR: unexpected `...`
+
+    let f = |_: ...| {};
+    //~^ ERROR C-variadic type `...` may not be nested inside another type
+    f(1i64)
+}
diff --git a/tests/ui/c-variadic/no-closure.stderr b/tests/ui/c-variadic/no-closure.stderr
new file mode 100644
index 00000000000..77bd106bb95
--- /dev/null
+++ b/tests/ui/c-variadic/no-closure.stderr
@@ -0,0 +1,35 @@
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/no-closure.rs:6:35
+   |
+LL | const F: extern "C" fn(...) = |_: ...| {};
+   |                                   ^^^
+
+error: unexpected `...`
+  --> $DIR/no-closure.rs:10:14
+   |
+LL |     let f = |...| {};
+   |              ^^^ not a valid pattern
+   |
+help: for a rest pattern, use `..` instead of `...`
+   |
+LL -     let f = |...| {};
+LL +     let f = |..| {};
+   |
+
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/no-closure.rs:14:17
+   |
+LL |     let f = |_: ...| {};
+   |                 ^^^
+
+error: `..` patterns are not allowed here
+  --> $DIR/no-closure.rs:10:14
+   |
+LL |     let f = |...| {};
+   |              ^^^
+   |
+   = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0743`.
diff --git a/tests/ui/c-variadic/valid.rs b/tests/ui/c-variadic/valid.rs
new file mode 100644
index 00000000000..5a0b32026dc
--- /dev/null
+++ b/tests/ui/c-variadic/valid.rs
@@ -0,0 +1,29 @@
+//@ run-pass
+#![feature(c_variadic)]
+
+// In rust (and C23 and above) `...` can be the only argument.
+unsafe extern "C" fn only_dot_dot_dot(mut ap: ...) -> i32 {
+    unsafe { ap.arg() }
+}
+
+unsafe extern "C-unwind" fn abi_c_unwind(mut ap: ...) -> i32 {
+    unsafe { ap.arg() }
+}
+
+#[allow(improper_ctypes_definitions)]
+unsafe extern "C" fn mix_int_float(mut ap: ...) -> (i64, f64, *const i32, f64) {
+    (ap.arg(), ap.arg(), ap.arg(), ap.arg())
+}
+
+fn main() {
+    unsafe {
+        assert_eq!(only_dot_dot_dot(32), 32);
+        assert_eq!(abi_c_unwind(32), 32);
+
+        // Passing more arguments than expected is allowed.
+        assert_eq!(only_dot_dot_dot(32, 1i64, core::ptr::null::<i32>(), 3.14f64), 32);
+
+        let ptr = &14i32 as *const i32;
+        assert_eq!(mix_int_float(12i64, 13.0f64, ptr, 15.0f64), (12, 13.0, ptr, 15.0));
+    }
+}
diff --git a/tests/ui/codegen/empty-static-libs-issue-108825.rs b/tests/ui/codegen/empty-static-libs-issue-108825.rs
index 4c644be0954..4f8e4420f72 100644
--- a/tests/ui/codegen/empty-static-libs-issue-108825.rs
+++ b/tests/ui/codegen/empty-static-libs-issue-108825.rs
@@ -15,4 +15,4 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
 }
 
 //~? NOTE native-static-libs:
-//~? NOTE Link against the following native artifacts when linking against this static library
+//~? NOTE link against the following native artifacts when linking against this static library
diff --git a/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr b/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr
index 12de4f1dc30..cf5b55a0ce2 100644
--- a/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr
+++ b/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr
@@ -21,10 +21,6 @@ LL |         [0u8; std::mem::size_of::<Self::A>()] == Self::P;
    |                                               ^^ no implementation for `[u8; std::mem::size_of::<Self::A>()] == <Self as T>::A`
    |
    = help: the trait `PartialEq<<Self as T>::A>` is not implemented for `[u8; std::mem::size_of::<Self::A>()]`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | pub trait T where [u8; std::mem::size_of::<Self::A>()]: PartialEq<<Self as T>::A> {
-   |             +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
index 0c57eddbe93..cc6a813b747 100644
--- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
+++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
@@ -14,7 +14,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                42                                              │ B
            }
@@ -25,7 +25,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                42                                              │ B
            }
diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
index 0c57eddbe93..cc6a813b747 100644
--- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
+++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
@@ -14,7 +14,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                42                                              │ B
            }
@@ -25,7 +25,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                42                                              │ B
            }
diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr
index 25d6f0461a9..70ae00af23f 100644
--- a/tests/ui/const-ptr/forbidden_slices.stderr
+++ b/tests/ui/const-ptr/forbidden_slices.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a null reference
 LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered a null reference
 LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -50,7 +50,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -61,7 +61,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e
 LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -72,7 +72,7 @@ error[E0080]: constructing invalid value at .<deref>[1]: encountered uninitializ
 LL | pub static S7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -83,7 +83,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | pub static S8: &[u64] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -94,7 +94,7 @@ error[E0080]: constructing invalid value: encountered a null reference
 LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -117,7 +117,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ
 LL | pub static R4: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -130,7 +130,7 @@ LL | pub static R5: &[u8] = unsafe {
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -141,7 +141,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e
 LL | pub static R6: &[bool] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -152,7 +152,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re
 LL | pub static R7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
index a8c7ee93971..239bca51fc9 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized
 LL | const BAR: &i32 = unsafe {
    | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC0<imm>╼                                     │ ╾──╼
            }
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
index 47e1c22cc2c..3c6d66ac5b6 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized
 LL | const BAR: &i32 = unsafe {
    | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC0<imm>╼                         │ ╾──────╼
            }
diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
index d4039e1952c..152eeababc5 100644
--- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
+++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (use-
 LL | const _X: &'static u8 = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
index 36183e28921..2861f82ec53 100644
--- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x00000001,
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                01 00 00 00                                     │ ....
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x00000000,
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                00 00 00 00                                     │ ....
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                01                                              │ .
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                03                                              │ .
            }
@@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0.1: encounter
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                78 00 00 00 ff ff ff ff                         │ x.......
            }
@@ -59,7 +59,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something
 LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                00 00 00 00                                     │ ....
            }
@@ -70,7 +70,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some
 LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                00                                              │ .
            }
@@ -81,7 +81,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some
 LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                00 00 00 00                                     │ ....
            }
@@ -92,7 +92,7 @@ error[E0080]: constructing invalid value: encountered 42, but expected something
 LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                2a 00 00 00                                     │ *...
            }
@@ -103,7 +103,7 @@ error[E0080]: constructing invalid value: encountered 20, but expected something
 LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                14 00 00 00                                     │ ....
            }
@@ -114,7 +114,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something
 LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                00 00 00 00 ╾ALLOC_ID╼                         │ ....╾──╼
            }
@@ -125,7 +125,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
@@ -136,7 +136,7 @@ error[E0080]: constructing invalid value: encountered an unaligned box (required
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
@@ -147,7 +147,7 @@ error[E0080]: constructing invalid value: encountered a null reference
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                00 00 00 00                                     │ ....
            }
@@ -158,7 +158,7 @@ error[E0080]: constructing invalid value: encountered a null box
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                00 00 00 00                                     │ ....
            }
@@ -169,7 +169,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (0x53
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                39 05 00 00                                     │ 9...
            }
@@ -180,7 +180,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (0x539[noal
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                39 05 00 00                                     │ 9...
            }
@@ -191,7 +191,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                00 00 00 00                                     │ ....
            }
@@ -202,7 +202,7 @@ error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                0d 00 00 00                                     │ ....
            }
@@ -213,7 +213,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
@@ -224,7 +224,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                01 00 00 00                                     │ ....
            }
@@ -235,7 +235,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
            }
@@ -246,7 +246,7 @@ error[E0080]: constructing invalid value at .0: encountered invalid reference me
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
            }
@@ -257,7 +257,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
            }
@@ -268,7 +268,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
@@ -279,7 +279,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered uninitialize
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
@@ -292,7 +292,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
@@ -303,7 +303,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
            }
@@ -314,7 +314,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ff ff ff 7f                         │ ╾──╼....
            }
@@ -325,7 +325,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (going beyo
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
            }
@@ -336,7 +336,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x03, but e
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
@@ -353,7 +353,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered 0x03, but ex
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
@@ -370,7 +370,7 @@ error[E0080]: constructing invalid value at .<deref>.1[0]: encountered 0x03, but
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
@@ -387,7 +387,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC17<imm>, but ex
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
@@ -398,7 +398,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC19<imm>, but ex
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
@@ -409,7 +409,7 @@ error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but ex
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
@@ -420,7 +420,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC22<imm>, but ex
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
@@ -431,7 +431,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>: encountered
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
@@ -442,7 +442,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 00 00 00 00                         │ ╾──╼....
            }
@@ -453,7 +453,7 @@ error[E0080]: constructing invalid value: encountered ALLOC27<imm>, but expected
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
@@ -464,7 +464,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un
 LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                01 00 00 00                                     │ ....
            }
@@ -475,7 +475,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                01 00 00 00 01 00 00 00                         │ ........
            }
@@ -486,7 +486,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                01 00 00 00 2a 00 00 00                         │ ....*...
            }
@@ -497,7 +497,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
@@ -510,7 +510,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem:
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
@@ -521,7 +521,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e
 LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
@@ -532,7 +532,7 @@ error[E0080]: constructing invalid value at .<deref>[1]: encountered uninitializ
 LL | pub static S7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID+0x2╼ 04 00 00 00                         │ ╾──╼....
            }
@@ -543,7 +543,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ
 LL | pub static R4: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
@@ -556,7 +556,7 @@ LL | pub static R5: &[u8] = unsafe {
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
@@ -567,7 +567,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e
 LL | pub static R6: &[bool] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
index c53326534fd..8e6dc66a40e 100644
--- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x000000000
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                01 00 00 00 00 00 00 00                         │ ........
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x000000000
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                00 00 00 00 00 00 00 00                         │ ........
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                01                                              │ .
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                03                                              │ .
            }
@@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0.1: encounter
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                78 00 00 00 ff ff ff ff                         │ x.......
            }
@@ -59,7 +59,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something
 LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                00 00 00 00 00 00 00 00                         │ ........
            }
@@ -70,7 +70,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some
 LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                00                                              │ .
            }
@@ -81,7 +81,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some
 LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                00 00 00 00 00 00 00 00                         │ ........
            }
@@ -92,7 +92,7 @@ error[E0080]: constructing invalid value: encountered 42, but expected something
 LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                2a 00 00 00                                     │ *...
            }
@@ -103,7 +103,7 @@ error[E0080]: constructing invalid value: encountered 20, but expected something
 LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                14 00 00 00                                     │ ....
            }
@@ -114,7 +114,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something
 LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                00 00 00 00 00 00 00 00 ╾ALLOC_ID╼ │ ........╾──────╼
            }
@@ -125,7 +125,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
@@ -136,7 +136,7 @@ error[E0080]: constructing invalid value: encountered an unaligned box (required
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
@@ -147,7 +147,7 @@ error[E0080]: constructing invalid value: encountered a null reference
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                00 00 00 00 00 00 00 00                         │ ........
            }
@@ -158,7 +158,7 @@ error[E0080]: constructing invalid value: encountered a null box
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                00 00 00 00 00 00 00 00                         │ ........
            }
@@ -169,7 +169,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (0x53
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                39 05 00 00 00 00 00 00                         │ 9.......
            }
@@ -180,7 +180,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (0x539[noal
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                39 05 00 00 00 00 00 00                         │ 9.......
            }
@@ -191,7 +191,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                00 00 00 00 00 00 00 00                         │ ........
            }
@@ -202,7 +202,7 @@ error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                0d 00 00 00 00 00 00 00                         │ ........
            }
@@ -213,7 +213,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
@@ -224,7 +224,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                01 00 00 00 00 00 00 00                         │ ........
            }
@@ -235,7 +235,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -246,7 +246,7 @@ error[E0080]: constructing invalid value at .0: encountered invalid reference me
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
            }
@@ -257,7 +257,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
            }
@@ -268,7 +268,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -279,7 +279,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered uninitialize
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -292,7 +292,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -303,7 +303,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -314,7 +314,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
            }
@@ -325,7 +325,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (going beyo
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -336,7 +336,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x03, but e
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
@@ -353,7 +353,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered 0x03, but ex
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
@@ -370,7 +370,7 @@ error[E0080]: constructing invalid value at .<deref>.1[0]: encountered 0x03, but
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
@@ -387,7 +387,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC17<imm>, but ex
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
@@ -398,7 +398,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC19<imm>, but ex
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
@@ -409,7 +409,7 @@ error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but ex
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -420,7 +420,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC22<imm>, but ex
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
@@ -431,7 +431,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>: encountered
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
@@ -442,7 +442,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -453,7 +453,7 @@ error[E0080]: constructing invalid value: encountered ALLOC27<imm>, but expected
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
@@ -464,7 +464,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un
 LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                01 00 00 00 00 00 00 00                         │ ........
            }
@@ -475,7 +475,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
            }
@@ -486,7 +486,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*.......
            }
@@ -497,7 +497,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -510,7 +510,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem:
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -521,7 +521,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e
 LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -532,7 +532,7 @@ error[E0080]: constructing invalid value at .<deref>[1]: encountered uninitializ
 LL | pub static S7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -543,7 +543,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ
 LL | pub static R4: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -556,7 +556,7 @@ LL | pub static R5: &[u8] = unsafe {
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -567,7 +567,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e
 LL | pub static R6: &[bool] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
diff --git a/tests/ui/consts/const-eval/transmute-const.stderr b/tests/ui/consts/const-eval/transmute-const.stderr
index ed3b3df70dd..53665c176a7 100644
--- a/tests/ui/consts/const-eval/transmute-const.stderr
+++ b/tests/ui/consts/const-eval/transmute-const.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0x03, but expected a boole
 LL | static FOO: bool = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                03                                              │ .
            }
diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr
index 5cbd6176c92..1efd9383229 100644
--- a/tests/ui/consts/const-eval/ub-enum.stderr
+++ b/tests/ui/consts/const-eval/ub-enum.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x01, but e
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -33,7 +33,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x0, but ex
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -81,7 +81,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -92,7 +92,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -103,7 +103,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0.1: encounter
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
index 86d6f8c52bc..1e4d425d78e 100644
--- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered ALLOC1<imm>, but expected
 LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼                         │ ╾──╼╾──╼
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected
 LL | const INVALID_VTABLE_SIZE: &dyn Trait =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼                         │ ╾──╼╾──╼
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC5<imm>, but exp
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼                         │ ╾──╼╾──╼
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC7<imm>, but exp
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼                         │ ╾──╼╾──╼
            }
@@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC9<imm>, but exp
 LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼                         │ ╾──╼╾──╼
            }
@@ -59,7 +59,7 @@ error[E0080]: constructing invalid value at .1: encountered a dangling reference
 LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC10<imm>╼ ╾ALLOC11╼                         │ ╾──╼╾──╼
            }
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
index a9518216dbd..a068991f324 100644
--- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered ALLOC1<imm>, but expected
 LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected
 LL | const INVALID_VTABLE_SIZE: &dyn Trait =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC5<imm>, but exp
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC7<imm>, but exp
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼
            }
@@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC9<imm>, but exp
 LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──────╼╾──────╼
            }
@@ -59,7 +59,7 @@ error[E0080]: constructing invalid value at .1: encountered a dangling reference
 LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼
            }
diff --git a/tests/ui/consts/const-eval/ub-int-array.stderr b/tests/ui/consts/const-eval/ub-int-array.stderr
index 10eb7c46c92..065bfd2c304 100644
--- a/tests/ui/consts/const-eval/ub-int-array.stderr
+++ b/tests/ui/consts/const-eval/ub-int-array.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at [0]: encountered uninitialized memor
 LL | const UNINIT_INT_0: [u32; 3] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
                __ __ __ __ 11 11 11 11 22 22 22 22             │ ░░░░....""""
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at [1]: encountered uninitialized memor
 LL | const UNINIT_INT_1: [u32; 3] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
                00 00 00 00 01 __ 01 01 02 02 __ 02             │ .....░....░.
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at [2]: encountered uninitialized memor
 LL | const UNINIT_INT_2: [u32; 3] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
                00 00 00 00 01 01 01 01 02 02 02 __             │ ...........░
            }
diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr
index 19ae66cf3c6..91c82efbc5e 100644
--- a/tests/ui/consts/const-eval/ub-nonnull.stderr
+++ b/tests/ui/consts/const-eval/ub-nonnull.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something
 LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -21,7 +21,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some
 LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -32,7 +32,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some
 LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -53,7 +53,7 @@ error[E0080]: constructing invalid value: encountered 42, but expected something
 LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -64,7 +64,7 @@ error[E0080]: constructing invalid value: encountered 20, but expected something
 LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -75,7 +75,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something
 LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
index 451ebb6eba1..c45f66c2925 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered an unaligned box (required
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value: encountered a null reference
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value: encountered a null box
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -87,7 +87,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (0x53
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -98,7 +98,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (0x539[noal
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -119,7 +119,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -140,7 +140,7 @@ error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -151,7 +151,7 @@ error[E0080]: constructing invalid value: encountered ALLOC2<imm>, but expected
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr
index b0f475fe938..aca0b13bb90 100644
--- a/tests/ui/consts/const-eval/ub-uninhabit.stderr
+++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr
@@ -10,7 +10,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr
index ecd1c768c28..b434970b677 100644
--- a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr
+++ b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>.<captured-va
 LL | const BAD_UPVAR: &dyn FnOnce() = &{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC0<imm>╼ ╾ALLOC1╼                         │ ╾──╼╾──╼
            }
diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr
index 108dfe6b27b..de1e1f8a2be 100644
--- a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr
+++ b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>.<captured-va
 LL | const BAD_UPVAR: &dyn FnOnce() = &{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
            }
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
index ab15ba826a5..c505e5cc8a2 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .0: encountered invalid reference me
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -44,7 +44,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -55,7 +55,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -66,7 +66,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered uninitialize
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -87,7 +87,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -98,7 +98,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -118,7 +118,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (going beyo
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -138,7 +138,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x03, but e
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -155,7 +155,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered 0x03, but ex
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -172,7 +172,7 @@ error[E0080]: constructing invalid value at .<deref>.1[0]: encountered 0x03, but
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -199,7 +199,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC12<imm>, but ex
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -210,7 +210,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC14<imm>, but ex
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -221,7 +221,7 @@ error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but ex
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -232,7 +232,7 @@ error[E0080]: constructing invalid value: encountered ALLOC17<imm>, but expected
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -243,7 +243,7 @@ error[E0080]: constructing invalid value: encountered ALLOC19<imm>, but expected
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -254,7 +254,7 @@ error[E0080]: constructing invalid value: encountered ALLOC21<imm>, but expected
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -265,7 +265,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC23<imm>, but ex
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -276,7 +276,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>: encountered
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -287,7 +287,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -298,7 +298,7 @@ error[E0080]: constructing invalid value: encountered ALLOC28<imm>, but expected
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -309,7 +309,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected
 LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -320,7 +320,7 @@ error[E0080]: constructing invalid value: encountered ALLOC31<imm>, but expected
 LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr
index 757bcea91c3..fb2311b9921 100644
--- a/tests/ui/consts/const-eval/union-ub.32bit.stderr
+++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0x2a, but expected a boole
 LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                2a                                              │ *
            }
diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr
index 757bcea91c3..fb2311b9921 100644
--- a/tests/ui/consts/const-eval/union-ub.64bit.stderr
+++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0x2a, but expected a boole
 LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
                2a                                              │ *
            }
diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr
index 16dee44d800..08656776468 100644
--- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr
+++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr
@@ -34,7 +34,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -45,7 +45,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | static IMMUT_MUT_REF_STATIC: &mut u16 = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
index 302e342bce6..96263998ad4 100644
--- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
+++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered
 LL | const MUT: Option<&mut i32> = helper();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered
 LL | const INT2PTR: Option<&mut i32> = helper_int2ptr();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered
 LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered
 LL | const DANGLING: Option<&mut i32> = helper_dangling();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered
 LL | static DANGLING_STATIC: Option<&mut i32> = helper_dangling();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
index 8be8b4bc50f..f9088c318a6 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered 0x0a, but expe
 LL |     const C: &bool = unsafe { std::mem::transmute(&S) };
    |     ^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr
index 65a46b62dae..4b034c81a61 100644
--- a/tests/ui/consts/dangling-alloc-id-ice.stderr
+++ b/tests/ui/consts/dangling-alloc-id-ice.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (use-
 LL | const FOO: &() = {
    | ^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr
index 2f600e494c4..248db694d52 100644
--- a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr
+++ b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (use-
 LL | pub static MAGIC_FFI_REF: &'static Wrapper = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr
index 47bb2e5e879..17b32383912 100644
--- a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr
+++ b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.y.<enum-variant(B)>.0: enco
 LL | fn main() {
    | ^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC0╼                                     │ ╾──╼
            }
diff --git a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr
index b4c9a4bd47e..c4f78e7bf9e 100644
--- a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr
+++ b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.y.<enum-variant(B)>.0: enco
 LL | fn main() {
    | ^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC0╼                         │ ╾──────╼
            }
diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr
index 68d1a72b71e..2c54200c8a2 100644
--- a/tests/ui/consts/issue-17718-const-bad-values.stderr
+++ b/tests/ui/consts/issue-17718-const-bad-values.stderr
@@ -14,7 +14,7 @@ error[E0080]: constructing invalid value: encountered mutable reference in `cons
 LL | const C2: &'static mut i32 = unsafe { &mut S };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $PTR, align: $PTR) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr
index e5340788167..cf97ed6e487 100644
--- a/tests/ui/consts/issue-63952.32bit.stderr
+++ b/tests/ui/consts/issue-63952.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC0<imm>╼ ff ff ff ff                         │ ╾──╼....
            }
diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr
index 27e74833fc5..4cea967314c 100644
--- a/tests/ui/consts/issue-63952.64bit.stderr
+++ b/tests/ui/consts/issue-63952.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata
 LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC0<imm>╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
            }
diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr
index 7488f7b7752..2653ff22f12 100644
--- a/tests/ui/consts/issue-79690.64bit.stderr
+++ b/tests/ui/consts/issue-79690.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .1: encountered a dangling reference
 LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
    | ^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
            }
diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr
index 137efde44b3..b35076b669e 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered mutable refere
 LL | static FOO: &&mut u32 = &&mut 42;
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | static OH_YES: &mut i32 = &mut 42;
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -38,7 +38,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | const BLUNT: &mut i32 = &mut 42;
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -49,7 +49,7 @@ error[E0080]: constructing invalid value: encountered mutable reference in `cons
 LL | const SUBTLE: &mut i32 = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -60,7 +60,7 @@ error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell`
 LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
    | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -71,7 +71,7 @@ error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell`
 LL | const MUH: Meh = Meh {
    | ^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -82,7 +82,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>.x: encounter
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -93,7 +93,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr
index 1ef20689985..d7c668a9812 100644
--- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell`
 LL | static REF: &AtomicI32 = &AtomicI32::new(42);
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC0╼                                     │ ╾──╼
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | static REFMUT: &mut i32 = &mut 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC1╼                                     │ ╾──╼
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell`
 LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC2╼                                     │ ╾──╼
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                ╾ALLOC3╼                                     │ ╾──╼
            }
diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr
index 06f78e679b1..f3bb49900b5 100644
--- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell`
 LL | static REF: &AtomicI32 = &AtomicI32::new(42);
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC0╼                         │ ╾──────╼
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | static REFMUT: &mut i32 = &mut 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC1╼                         │ ╾──────╼
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell`
 LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC2╼                         │ ╾──────╼
            }
@@ -37,7 +37,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p
 LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
                ╾ALLOC3╼                         │ ╾──────╼
            }
diff --git a/tests/ui/consts/validate_never_arrays.stderr b/tests/ui/consts/validate_never_arrays.stderr
index 0f503df4060..3c405e8d3cd 100644
--- a/tests/ui/consts/validate_never_arrays.stderr
+++ b/tests/ui/consts/validate_never_arrays.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un
 LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
    | ^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/crate-loading/invalid-rlib.rs b/tests/ui/crate-loading/invalid-rlib.rs
index 6b463526244..24293f88b1c 100644
--- a/tests/ui/crate-loading/invalid-rlib.rs
+++ b/tests/ui/crate-loading/invalid-rlib.rs
@@ -6,6 +6,3 @@
 #![no_std]
 use ::foo; //~ ERROR invalid metadata files for crate `foo`
 //~| NOTE failed to mmap file
-//~^^ ERROR invalid metadata files for crate `foo`
-//~| NOTE failed to mmap file
-//~| NOTE duplicate diagnostic
diff --git a/tests/ui/crate-loading/invalid-rlib.stderr b/tests/ui/crate-loading/invalid-rlib.stderr
index 63bb1b95cbb..ad3ab729a5d 100644
--- a/tests/ui/crate-loading/invalid-rlib.stderr
+++ b/tests/ui/crate-loading/invalid-rlib.stderr
@@ -6,15 +6,6 @@ LL | use ::foo;
    |
    = note: failed to mmap file 'auxiliary/libfoo.rlib'
 
-error[E0786]: found invalid metadata files for crate `foo`
-  --> $DIR/invalid-rlib.rs:7:7
-   |
-LL | use ::foo;
-   |       ^^^
-   |
-   = note: failed to mmap file 'auxiliary/libfoo.rlib'
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0786`.
diff --git a/tests/ui/drop/if-let-super-let.rs b/tests/ui/drop/if-let-super-let.rs
new file mode 100644
index 00000000000..c6543e6d3dc
--- /dev/null
+++ b/tests/ui/drop/if-let-super-let.rs
@@ -0,0 +1,112 @@
+//! Test for #145328: ensure the lifetime of a `super let` binding within an `if let` scrutinee is
+//! at most the scope of the `if` condition's temporaries. Additionally, test `pin!` since it's
+//! implemented in terms of `super let` and exposes this behavior.
+//@ run-pass
+//@ revisions: e2021 e2024
+//@ [e2021] edition: 2021
+//@ [e2024] edition: 2024
+
+#![feature(if_let_guard)]
+#![feature(super_let)]
+#![expect(irrefutable_let_patterns)]
+
+use std::cell::RefCell;
+use std::pin::pin;
+
+fn main() {
+    // The `super let` bindings here should have the same scope as `if let` temporaries.
+    // In Rust 2021, this means it lives past the end of the `if` expression.
+    // In Rust 2024, this means it lives to the end of the `if`'s success block.
+    assert_drop_order(0..=2, |o| {
+        #[cfg(e2021)]
+        (
+            if let _ = { super let _x = o.log(2); } { o.push(0) },
+            o.push(1),
+        );
+        #[cfg(e2024)]
+        (
+            if let _ = { super let _x = o.log(1); } { o.push(0) },
+            o.push(2),
+        );
+    });
+    assert_drop_order(0..=2, |o| {
+        #[cfg(e2021)]
+        (
+            if let true = { super let _x = o.log(2); false } {} else { o.push(0) },
+            o.push(1),
+        );
+        #[cfg(e2024)]
+        (
+            if let true = { super let _x = o.log(0); false } {} else { o.push(1) },
+            o.push(2),
+        );
+    });
+
+    // `pin!` should behave likewise.
+    assert_drop_order(0..=2, |o| {
+        #[cfg(e2021)] (if let _ = pin!(o.log(2)) { o.push(0) }, o.push(1));
+        #[cfg(e2024)] (if let _ = pin!(o.log(1)) { o.push(0) }, o.push(2));
+    });
+    assert_drop_order(0..=2, |o| {
+        #[cfg(e2021)]
+        (
+            if let None = Some(pin!(o.log(2))) {} else { o.push(0) },
+            o.push(1),
+        );
+        #[cfg(e2024)]
+        (
+            if let None = Some(pin!(o.log(0))) {} else { o.push(1) },
+            o.push(2),
+        );
+    });
+
+    // `super let` bindings' scope should also be consistent with `if let` temporaries in guards.
+    // Here, that means the `super let` binding in the second guard condition operand should be
+    // dropped before the first operand's temporary. This is consistent across Editions.
+    assert_drop_order(0..=1, |o| {
+        match () {
+            _ if let _ = o.log(1)
+                && let _ = { super let _x = o.log(0); } => {}
+            _ => unreachable!(),
+        }
+    });
+    assert_drop_order(0..=1, |o| {
+        match () {
+            _ if let _ = o.log(1)
+                && let _ = pin!(o.log(0)) => {}
+            _ => unreachable!(),
+        }
+    });
+}
+
+// # Test scaffolding...
+
+struct DropOrder(RefCell<Vec<u64>>);
+struct LogDrop<'o>(&'o DropOrder, u64);
+
+impl DropOrder {
+    fn log(&self, n: u64) -> LogDrop<'_> {
+        LogDrop(self, n)
+    }
+    fn push(&self, n: u64) {
+        self.0.borrow_mut().push(n);
+    }
+}
+
+impl<'o> Drop for LogDrop<'o> {
+    fn drop(&mut self) {
+        self.0.push(self.1);
+    }
+}
+
+#[track_caller]
+fn assert_drop_order(
+    ex: impl IntoIterator<Item = u64>,
+    f: impl Fn(&DropOrder),
+) {
+    let order = DropOrder(RefCell::new(Vec::new()));
+    f(&order);
+    let order = order.0.into_inner();
+    let expected: Vec<u64> = ex.into_iter().collect();
+    assert_eq!(order, expected);
+}
diff --git a/tests/ui/error-emitter/multiline-removal-suggestion.svg b/tests/ui/error-emitter/multiline-removal-suggestion.svg
index 9c9bd163ecd..7a88ac55b23 100644
--- a/tests/ui/error-emitter/multiline-removal-suggestion.svg
+++ b/tests/ui/error-emitter/multiline-removal-suggestion.svg
@@ -1,4 +1,4 @@
-<svg width="2322px" height="4322px" xmlns="http://www.w3.org/2000/svg">
+<svg width="2238px" height="3890px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
     .bg { background: #000000 }
@@ -129,375 +129,327 @@
 </tspan>
     <tspan x="10px" y="982px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan>
 </tspan>
-    <tspan x="10px" y="1000px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:16:10: 16:13}&gt;&gt; as IntoIterator&gt;::IntoIter = _`</tspan>
+    <tspan x="10px" y="1000px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
-    <tspan x="10px" y="1018px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="1018px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
-    <tspan x="10px" y="1036px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:16:10: 16:13}&gt;&gt; as IntoIterator&gt;::Item = _`</tspan>
+    <tspan x="10px" y="1036px">
 </tspan>
-    <tspan x="10px" y="1054px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="1054px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="1072px"><tspan>           `Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:16:10: 16:13}&gt;&gt;: IntoIterator`</tspan>
+    <tspan x="10px" y="1072px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:32:6</tspan>
 </tspan>
-    <tspan x="10px" y="1090px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="1090px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1108px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="1108px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="1126px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="1126px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                  </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="1144px">
+    <tspan x="10px" y="1144px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1162px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="1162px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
 </tspan>
-    <tspan x="10px" y="1180px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:32:6</tspan>
+    <tspan x="10px" y="1180px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
 </tspan>
-    <tspan x="10px" y="1198px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1198px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan>
 </tspan>
-    <tspan x="10px" y="1216px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .flatten()</tspan>
+    <tspan x="10px" y="1216px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan>
 </tspan>
-    <tspan x="10px" y="1234px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                  </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="1234px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;` and `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;: Iterator` trivially holds</tspan>
 </tspan>
     <tspan x="10px" y="1252px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1270px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
+    <tspan x="10px" y="1270px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan>            ts.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="1288px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
+    <tspan x="10px" y="1288px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-                 .map(|t| (is_true, t))</tspan>
 </tspan>
-    <tspan x="10px" y="1306px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan>
+    <tspan x="10px" y="1306px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan>            ts.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="1324px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan>
+    <tspan x="10px" y="1324px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1342px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;` and `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;: Iterator` trivially holds</tspan>
+    <tspan x="10px" y="1342px">
 </tspan>
-    <tspan x="10px" y="1360px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1360px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="1378px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan>            ts.into_iter()</tspan>
+    <tspan x="10px" y="1378px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:28:2</tspan>
 </tspan>
-    <tspan x="10px" y="1396px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-                 .map(|t| (is_true, t))</tspan>
+    <tspan x="10px" y="1396px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1414px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan>            ts.into_iter()</tspan>
+    <tspan x="10px" y="1414px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan>     hm.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="1432px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1432px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
 </tspan>
-    <tspan x="10px" y="1450px">
+    <tspan x="10px" y="1450px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             ts.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="1468px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="1468px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 .map(|t| (is_true, t))</tspan>
 </tspan>
-    <tspan x="10px" y="1486px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:28:2</tspan>
+    <tspan x="10px" y="1486px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 .flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="1504px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1504px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         })</tspan>
 </tspan>
-    <tspan x="10px" y="1522px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan>     hm.into_iter()</tspan>
+    <tspan x="10px" y="1522px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="1540px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
+    <tspan x="10px" y="1540px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1558px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             ts.into_iter()</tspan>
+    <tspan x="10px" y="1558px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
 </tspan>
-    <tspan x="10px" y="1576px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 .map(|t| (is_true, t))</tspan>
+    <tspan x="10px" y="1576px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
 </tspan>
-    <tspan x="10px" y="1594px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 .flatten()</tspan>
+    <tspan x="10px" y="1594px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan>
 </tspan>
-    <tspan x="10px" y="1612px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         })</tspan>
+    <tspan x="10px" y="1612px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan>
 </tspan>
-    <tspan x="10px" y="1630px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="1630px">
 </tspan>
-    <tspan x="10px" y="1648px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1648px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;`, but its trait bounds were not satisfied</tspan>
 </tspan>
-    <tspan x="10px" y="1666px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
+    <tspan x="10px" y="1666px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:35:4</tspan>
 </tspan>
-    <tspan x="10px" y="1684px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
+    <tspan x="10px" y="1684px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1702px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan>
+    <tspan x="10px" y="1702px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan>     hm.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="1720px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan>
+    <tspan x="10px" y="1720px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
 </tspan>
-    <tspan x="10px" y="1738px">
+    <tspan x="10px" y="1738px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             ts.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="1756px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;`, but its trait bounds were not satisfied</tspan>
+    <tspan x="10px" y="1756px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .map(|t| (is_true, t))</tspan>
 </tspan>
-    <tspan x="10px" y="1774px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:35:4</tspan>
+    <tspan x="10px" y="1774px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan>  </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1792px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1792px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="1810px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan>     hm.into_iter()</tspan>
+    <tspan x="10px" y="1810px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .collect()</tspan>
 </tspan>
-    <tspan x="10px" y="1828px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
+    <tspan x="10px" y="1828px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan>
 </tspan>
-    <tspan x="10px" y="1846px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             ts.into_iter()</tspan>
+    <tspan x="10px" y="1846px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan>
 </tspan>
-    <tspan x="10px" y="1864px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .map(|t| (is_true, t))</tspan>
+    <tspan x="10px" y="1864px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1882px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan>  </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1882px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="1900px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .flatten()</tspan>
+    <tspan x="10px" y="1900px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan>
 </tspan>
-    <tspan x="10px" y="1918px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .collect()</tspan>
+    <tspan x="10px" y="1918px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
-    <tspan x="10px" y="1936px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan>
+    <tspan x="10px" y="1936px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
-    <tspan x="10px" y="1954px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan>
+    <tspan x="10px" y="1954px">
 </tspan>
-    <tspan x="10px" y="1972px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1972px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="1990px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="1990px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:43:7</tspan>
 </tspan>
-    <tspan x="10px" y="2008px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan>
+    <tspan x="10px" y="2008px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2026px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:31:10: 31:13}&gt;&gt; as IntoIterator&gt;::IntoIter = _`</tspan>
+    <tspan x="10px" y="2026px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             }).flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="2044px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="2044px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="2062px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:31:10: 31:13}&gt;&gt; as IntoIterator&gt;::Item = _`</tspan>
+    <tspan x="10px" y="2062px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2080px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="2080px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
 </tspan>
-    <tspan x="10px" y="2098px"><tspan>           `Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:31:10: 31:13}&gt;&gt;: IntoIterator`</tspan>
+    <tspan x="10px" y="2098px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
 </tspan>
-    <tspan x="10px" y="2116px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="2116px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan>
 </tspan>
-    <tspan x="10px" y="2134px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="2134px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan>
 </tspan>
-    <tspan x="10px" y="2152px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="2152px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;` and `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;: Iterator` trivially holds</tspan>
 </tspan>
-    <tspan x="10px" y="2170px">
+    <tspan x="10px" y="2170px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2188px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="2188px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan>            ts.into_iter()</tspan><tspan class="fg-ansi256-009">.map(|t| {</tspan>
 </tspan>
-    <tspan x="10px" y="2206px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:43:7</tspan>
+    <tspan x="10px" y="2206px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-                 (is_true, t)</tspan>
 </tspan>
-    <tspan x="10px" y="2224px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="2224px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-             })</tspan><tspan>.flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="2242px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             }).flatten()</tspan>
+    <tspan x="10px" y="2242px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan>            ts.into_iter().flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="2260px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="2260px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2278px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="2278px">
 </tspan>
-    <tspan x="10px" y="2296px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
+    <tspan x="10px" y="2296px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="2314px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
+    <tspan x="10px" y="2314px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:39:2</tspan>
 </tspan>
-    <tspan x="10px" y="2332px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan>
+    <tspan x="10px" y="2332px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2350px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan>
+    <tspan x="10px" y="2350px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan>     hm.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="2368px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;` and `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;: Iterator` trivially holds</tspan>
+    <tspan x="10px" y="2368px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
 </tspan>
-    <tspan x="10px" y="2386px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="2386px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             ts.into_iter().map(|t| {</tspan>
 </tspan>
-    <tspan x="10px" y="2404px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan>            ts.into_iter()</tspan><tspan class="fg-ansi256-009">.map(|t| {</tspan>
+    <tspan x="10px" y="2404px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 (is_true, t)</tspan>
 </tspan>
-    <tspan x="10px" y="2422px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-                 (is_true, t)</tspan>
+    <tspan x="10px" y="2422px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             }).flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="2440px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-             })</tspan><tspan>.flatten()</tspan>
+    <tspan x="10px" y="2440px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         })</tspan>
 </tspan>
-    <tspan x="10px" y="2458px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan>            ts.into_iter().flatten()</tspan>
+    <tspan x="10px" y="2458px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
     <tspan x="10px" y="2476px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2494px">
+    <tspan x="10px" y="2494px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
 </tspan>
-    <tspan x="10px" y="2512px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="2512px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
 </tspan>
-    <tspan x="10px" y="2530px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:39:2</tspan>
+    <tspan x="10px" y="2530px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan>
 </tspan>
-    <tspan x="10px" y="2548px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="2548px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan>
 </tspan>
-    <tspan x="10px" y="2566px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan>     hm.into_iter()</tspan>
+    <tspan x="10px" y="2566px">
 </tspan>
-    <tspan x="10px" y="2584px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
+    <tspan x="10px" y="2584px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;`, but its trait bounds were not satisfied</tspan>
 </tspan>
-    <tspan x="10px" y="2602px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             ts.into_iter().map(|t| {</tspan>
+    <tspan x="10px" y="2602px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:46:4</tspan>
 </tspan>
-    <tspan x="10px" y="2620px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 (is_true, t)</tspan>
+    <tspan x="10px" y="2620px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2638px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             }).flatten()</tspan>
+    <tspan x="10px" y="2638px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan>     hm.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="2656px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         })</tspan>
+    <tspan x="10px" y="2656px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
 </tspan>
-    <tspan x="10px" y="2674px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="2674px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             ts.into_iter().map(|t| {</tspan>
 </tspan>
-    <tspan x="10px" y="2692px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="2692px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 (is_true, t)</tspan>
 </tspan>
-    <tspan x="10px" y="2710px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
+    <tspan x="10px" y="2710px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan>  </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2728px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
+    <tspan x="10px" y="2728px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="2746px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan>
+    <tspan x="10px" y="2746px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .collect()</tspan>
 </tspan>
-    <tspan x="10px" y="2764px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan>
+    <tspan x="10px" y="2764px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan>
 </tspan>
-    <tspan x="10px" y="2782px">
+    <tspan x="10px" y="2782px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan>
 </tspan>
-    <tspan x="10px" y="2800px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;`, but its trait bounds were not satisfied</tspan>
+    <tspan x="10px" y="2800px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2818px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:46:4</tspan>
+    <tspan x="10px" y="2818px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2836px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="2836px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan>
 </tspan>
-    <tspan x="10px" y="2854px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan>     hm.into_iter()</tspan>
+    <tspan x="10px" y="2854px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
-    <tspan x="10px" y="2872px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
+    <tspan x="10px" y="2872px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
-    <tspan x="10px" y="2890px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             ts.into_iter().map(|t| {</tspan>
+    <tspan x="10px" y="2890px">
 </tspan>
-    <tspan x="10px" y="2908px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 (is_true, t)</tspan>
+    <tspan x="10px" y="2908px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="2926px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan>  </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="2926px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:53:28</tspan>
 </tspan>
-    <tspan x="10px" y="2944px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .flatten()</tspan>
+    <tspan x="10px" y="2944px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="2962px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .collect()</tspan>
+    <tspan x="10px" y="2962px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .map(|t| (is_true, t)).flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="2980px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan>
+    <tspan x="10px" y="2980px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                                        </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="2998px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan>
+    <tspan x="10px" y="2998px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3016px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3016px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
 </tspan>
-    <tspan x="10px" y="3034px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3034px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
 </tspan>
-    <tspan x="10px" y="3052px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan>
+    <tspan x="10px" y="3052px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan>
 </tspan>
-    <tspan x="10px" y="3070px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:41:23: 41:26}&gt;&gt; as IntoIterator&gt;::IntoIter = _`</tspan>
+    <tspan x="10px" y="3070px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan>
 </tspan>
-    <tspan x="10px" y="3088px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="3088px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;` and `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;: Iterator` trivially holds</tspan>
 </tspan>
-    <tspan x="10px" y="3106px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:41:23: 41:26}&gt;&gt; as IntoIterator&gt;::Item = _`</tspan>
+    <tspan x="10px" y="3106px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3124px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="3124px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan>            ts.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="3142px"><tspan>           `Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:41:23: 41:26}&gt;&gt;: IntoIterator`</tspan>
+    <tspan x="10px" y="3142px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-                 .map(|t| (is_true, t))</tspan><tspan>.flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="3160px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="3160px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan>            ts.into_iter().flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="3178px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="3178px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3196px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}&gt;&gt;: Iterator`</tspan>
+    <tspan x="10px" y="3196px">
 </tspan>
-    <tspan x="10px" y="3214px">
+    <tspan x="10px" y="3214px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="3232px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="3232px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:50:2</tspan>
 </tspan>
-    <tspan x="10px" y="3250px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:53:28</tspan>
+    <tspan x="10px" y="3250px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3268px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3268px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan>     hm.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="3286px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .map(|t| (is_true, t)).flatten()</tspan>
+    <tspan x="10px" y="3286px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
 </tspan>
-    <tspan x="10px" y="3304px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                                        </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="3304px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             ts.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="3322px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3322px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 .map(|t| (is_true, t)).flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="3340px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
+    <tspan x="10px" y="3340px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         })</tspan>
 </tspan>
-    <tspan x="10px" y="3358px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
+    <tspan x="10px" y="3358px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
 </tspan>
-    <tspan x="10px" y="3376px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan>
+    <tspan x="10px" y="3376px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3394px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan>
+    <tspan x="10px" y="3394px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
 </tspan>
-    <tspan x="10px" y="3412px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;` and `std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;: Iterator` trivially holds</tspan>
+    <tspan x="10px" y="3412px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
 </tspan>
-    <tspan x="10px" y="3430px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3430px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan>
 </tspan>
-    <tspan x="10px" y="3448px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan>            ts.into_iter()</tspan>
+    <tspan x="10px" y="3448px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan>
 </tspan>
-    <tspan x="10px" y="3466px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">-                 .map(|t| (is_true, t))</tspan><tspan>.flatten()</tspan>
+    <tspan x="10px" y="3466px">
 </tspan>
-    <tspan x="10px" y="3484px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan>            ts.into_iter().flatten()</tspan>
+    <tspan x="10px" y="3484px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;`, but its trait bounds were not satisfied</tspan>
 </tspan>
-    <tspan x="10px" y="3502px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3502px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:56:4</tspan>
 </tspan>
-    <tspan x="10px" y="3520px">
+    <tspan x="10px" y="3520px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3538px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="3538px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan>     hm.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="3556px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:50:2</tspan>
+    <tspan x="10px" y="3556px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
 </tspan>
-    <tspan x="10px" y="3574px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3574px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             ts.into_iter()</tspan>
 </tspan>
-    <tspan x="10px" y="3592px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan>     hm.into_iter()</tspan>
+    <tspan x="10px" y="3592px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .map(|t| (is_true, t)).flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="3610px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
+    <tspan x="10px" y="3610px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         })</tspan>
 </tspan>
-    <tspan x="10px" y="3628px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>             ts.into_iter()</tspan>
+    <tspan x="10px" y="3628px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .flatten()</tspan>
 </tspan>
-    <tspan x="10px" y="3646px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>                 .map(|t| (is_true, t)).flatten()</tspan>
+    <tspan x="10px" y="3646px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .collect()</tspan>
 </tspan>
-    <tspan x="10px" y="3664px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan>         })</tspan>
+    <tspan x="10px" y="3664px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan>
 </tspan>
-    <tspan x="10px" y="3682px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet&lt;u8&gt;)` is not an iterator</tspan>
+    <tspan x="10px" y="3682px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan>
 </tspan>
     <tspan x="10px" y="3700px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3718px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet&lt;u8&gt;)`</tspan>
+    <tspan x="10px" y="3718px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
 </tspan>
-    <tspan x="10px" y="3736px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet&lt;u8&gt;)` to implement `IntoIterator`</tspan>
+    <tspan x="10px" y="3736px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan>
 </tspan>
-    <tspan x="10px" y="3754px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan>
+    <tspan x="10px" y="3754px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
-    <tspan x="10px" y="3772px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan>
+    <tspan x="10px" y="3772px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;: Iterator`</tspan>
 </tspan>
     <tspan x="10px" y="3790px">
 </tspan>
-    <tspan x="10px" y="3808px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;`, but its trait bounds were not satisfied</tspan>
+    <tspan x="10px" y="3808px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 12 previous errors</tspan>
 </tspan>
-    <tspan x="10px" y="3826px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/multiline-removal-suggestion.rs:56:4</tspan>
+    <tspan x="10px" y="3826px">
 </tspan>
-    <tspan x="10px" y="3844px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+    <tspan x="10px" y="3844px"><tspan class="bold">Some errors have detailed explanations: E0277, E0599.</tspan>
 </tspan>
-    <tspan x="10px" y="3862px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan>     hm.into_iter()</tspan>
+    <tspan x="10px" y="3862px"><tspan class="bold">For more information about an error, try `rustc --explain E0277`.</tspan>
 </tspan>
-    <tspan x="10px" y="3880px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .map(|(is_true, ts)| {</tspan>
-</tspan>
-    <tspan x="10px" y="3898px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             ts.into_iter()</tspan>
-</tspan>
-    <tspan x="10px" y="3916px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>                 .map(|t| (is_true, t)).flatten()</tspan>
-</tspan>
-    <tspan x="10px" y="3934px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         })</tspan>
-</tspan>
-    <tspan x="10px" y="3952px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .flatten()</tspan>
-</tspan>
-    <tspan x="10px" y="3970px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         .collect()</tspan>
-</tspan>
-    <tspan x="10px" y="3988px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan>
-</tspan>
-    <tspan x="10px" y="4006px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan>
-</tspan>
-    <tspan x="10px" y="4024px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
-</tspan>
-    <tspan x="10px" y="4042px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
-</tspan>
-    <tspan x="10px" y="4060px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan>
-</tspan>
-    <tspan x="10px" y="4078px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:53:10: 53:13}&gt;&gt; as IntoIterator&gt;::IntoIter = _`</tspan>
-</tspan>
-    <tspan x="10px" y="4096px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;: Iterator`</tspan>
-</tspan>
-    <tspan x="10px" y="4114px"><tspan>           `&lt;Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:53:10: 53:13}&gt;&gt; as IntoIterator&gt;::Item = _`</tspan>
-</tspan>
-    <tspan x="10px" y="4132px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;: Iterator`</tspan>
-</tspan>
-    <tspan x="10px" y="4150px"><tspan>           `Flatten&lt;Map&lt;std::vec::IntoIter&lt;HashSet&lt;u8&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:53:10: 53:13}&gt;&gt;: IntoIterator`</tspan>
-</tspan>
-    <tspan x="10px" y="4168px"><tspan>           which is required by `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;: Iterator`</tspan>
-</tspan>
-    <tspan x="10px" y="4186px"><tspan>           `Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;: Iterator`</tspan>
-</tspan>
-    <tspan x="10px" y="4204px"><tspan>           which is required by `&amp;mut Flatten&lt;Map&lt;std::collections::hash_map::IntoIter&lt;bool, Vec&lt;HashSet&lt;u8&gt;&gt;&gt;, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}&gt;&gt;: Iterator`</tspan>
-</tspan>
-    <tspan x="10px" y="4222px">
-</tspan>
-    <tspan x="10px" y="4240px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 12 previous errors</tspan>
-</tspan>
-    <tspan x="10px" y="4258px">
-</tspan>
-    <tspan x="10px" y="4276px"><tspan class="bold">Some errors have detailed explanations: E0277, E0599.</tspan>
-</tspan>
-    <tspan x="10px" y="4294px"><tspan class="bold">For more information about an error, try `rustc --explain E0277`.</tspan>
-</tspan>
-    <tspan x="10px" y="4312px">
+    <tspan x="10px" y="3880px">
 </tspan>
   </text>
 
diff --git a/tests/ui/feature-gates/feature-gate-target-feature-inline-always.rs b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.rs
new file mode 100644
index 00000000000..181f9a21000
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.rs
@@ -0,0 +1,9 @@
+//@ only-aarch64
+#[inline(always)]
+//~^ ERROR cannot use `#[inline(always)]` with `#[target_feature]`
+#[target_feature(enable="fp16")]
+fn test() {
+
+}
+
+fn main() { }
diff --git a/tests/ui/feature-gates/feature-gate-target-feature-inline-always.stderr b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.stderr
new file mode 100644
index 00000000000..de54844bc29
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot use `#[inline(always)]` with `#[target_feature]`
+  --> $DIR/feature-gate-target-feature-inline-always.rs:2:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information
+   = help: add `#![feature(target_feature_inline_always)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index e5dae4c0069..c2653dd82a9 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -917,50 +917,50 @@ mod no_builtins {
 
 #[recursion_limit="0200"]
 //~^ WARN crate-level attribute should be an inner attribute
-//~| HELP add a `!`
 mod recursion_limit {
+    //~^ NOTE This attribute does not have an `!`, which means it is applied to this module
     mod inner { #![recursion_limit="0200"] }
-//~^ WARN crate-level attribute should be in the root module
+//~^ WARN the `#![recursion_limit]` attribute can only be used at the crate root
 
     #[recursion_limit="0200"] fn f() { }
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this function
 
     #[recursion_limit="0200"] struct S;
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this struct
 
     #[recursion_limit="0200"] type T = S;
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
 
     #[recursion_limit="0200"] impl S { }
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
 }
 
 #[type_length_limit="0100"]
 //~^ WARN crate-level attribute should be an inner attribute
-//~| HELP add a `!`
 mod type_length_limit {
+    //~^ NOTE This attribute does not have an `!`, which means it is applied to this module
     mod inner { #![type_length_limit="0100"] }
-//~^ WARN crate-level attribute should be in the root module
+//~^ WARN the `#![type_length_limit]` attribute can only be used at the crate root
 
     #[type_length_limit="0100"] fn f() { }
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this function
 
     #[type_length_limit="0100"] struct S;
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this struct
 
     #[type_length_limit="0100"] type T = S;
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
 
     #[type_length_limit="0100"] impl S { }
     //~^ WARN crate-level attribute should be an inner attribute
-    //~| HELP add a `!`
+    //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
 }
 
 fn main() {}
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index ef74a00e5a1..4a3520972bf 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -291,28 +291,6 @@ help: add a `!`
 LL | #![no_builtins]
    |  +
 
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:1
-   |
-LL | #[recursion_limit="0200"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL | #![recursion_limit="0200"]
-   |  +
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:1
-   |
-LL | #[type_length_limit="0100"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL | #![type_length_limit="0100"]
-   |  +
-
 warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1
    |
@@ -757,106 +735,6 @@ help: add a `!`
 LL |     #![no_builtins] impl S { }
    |      +
 
-warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:922:17
-   |
-LL |     mod inner { #![recursion_limit="0200"] }
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5
-   |
-LL |     #[recursion_limit="0200"] fn f() { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![recursion_limit="0200"] fn f() { }
-   |      +
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5
-   |
-LL |     #[recursion_limit="0200"] struct S;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![recursion_limit="0200"] struct S;
-   |      +
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5
-   |
-LL |     #[recursion_limit="0200"] type T = S;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![recursion_limit="0200"] type T = S;
-   |      +
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5
-   |
-LL |     #[recursion_limit="0200"] impl S { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![recursion_limit="0200"] impl S { }
-   |      +
-
-warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:946:17
-   |
-LL |     mod inner { #![type_length_limit="0100"] }
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5
-   |
-LL |     #[type_length_limit="0100"] fn f() { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![type_length_limit="0100"] fn f() { }
-   |      +
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5
-   |
-LL |     #[type_length_limit="0100"] struct S;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![type_length_limit="0100"] struct S;
-   |      +
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5
-   |
-LL |     #[type_length_limit="0100"] type T = S;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![type_length_limit="0100"] type T = S;
-   |      +
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5
-   |
-LL |     #[type_length_limit="0100"] impl S { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: add a `!`
-   |
-LL |     #![type_length_limit="0100"] impl S { }
-   |      +
-
 warning: `#[macro_use]` attribute cannot be used on functions
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5
    |
@@ -1476,6 +1354,146 @@ note: This attribute does not have an `!`, which means it is applied to this imp
 LL |     #[crate_name = "0900"] impl S { }
    |                            ^^^^^^^^^^
 
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:1
+   |
+LL | #[recursion_limit="0200"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this module
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:1
+   |
+LL | / mod recursion_limit {
+LL | |
+LL | |     mod inner { #![recursion_limit="0200"] }
+...  |
+LL | | }
+   | |_^
+
+warning: the `#![recursion_limit]` attribute can only be used at the crate root
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:922:17
+   |
+LL |     mod inner { #![recursion_limit="0200"] }
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5
+   |
+LL |     #[recursion_limit="0200"] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this function
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:31
+   |
+LL |     #[recursion_limit="0200"] fn f() { }
+   |                               ^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5
+   |
+LL |     #[recursion_limit="0200"] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this struct
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:31
+   |
+LL |     #[recursion_limit="0200"] struct S;
+   |                               ^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5
+   |
+LL |     #[recursion_limit="0200"] type T = S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this type alias
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:31
+   |
+LL |     #[recursion_limit="0200"] type T = S;
+   |                               ^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5
+   |
+LL |     #[recursion_limit="0200"] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this implementation block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:31
+   |
+LL |     #[recursion_limit="0200"] impl S { }
+   |                               ^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:1
+   |
+LL | #[type_length_limit="0100"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this module
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:1
+   |
+LL | / mod type_length_limit {
+LL | |
+LL | |     mod inner { #![type_length_limit="0100"] }
+...  |
+LL | | }
+   | |_^
+
+warning: the `#![type_length_limit]` attribute can only be used at the crate root
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:946:17
+   |
+LL |     mod inner { #![type_length_limit="0100"] }
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5
+   |
+LL |     #[type_length_limit="0100"] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this function
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:33
+   |
+LL |     #[type_length_limit="0100"] fn f() { }
+   |                                 ^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5
+   |
+LL |     #[type_length_limit="0100"] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this struct
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:33
+   |
+LL |     #[type_length_limit="0100"] struct S;
+   |                                 ^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5
+   |
+LL |     #[type_length_limit="0100"] type T = S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this type alias
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:33
+   |
+LL |     #[type_length_limit="0100"] type T = S;
+   |                                 ^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5
+   |
+LL |     #[type_length_limit="0100"] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this implementation block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:33
+   |
+LL |     #[type_length_limit="0100"] impl S { }
+   |                                 ^^^^^^^^^^
+
 warning: `#[should_panic]` attribute cannot be used on crates
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1
    |
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
index b58c3a6720d..14d5de0261d 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![deny(unused_assignments, unused_variables)]
+#![deny(unused_assignments)]
 #![allow(unused_mut)]
 struct Object;
 
@@ -8,15 +8,15 @@ fn change_object(object: &mut Object) { //~ HELP you might have meant to mutate
    *object = object2; //~ ERROR mismatched types
 }
 
-fn change_object2(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
-   //~^ HELP you might have meant to mutate
+fn change_object2(object: &mut Object) {
+    //~^ HELP you might have meant to mutate
    let object2 = Object;
    *object = object2;
    //~^ ERROR `object2` does not live long enough
    //~| ERROR value assigned to `object` is never read
 }
 
-fn change_object3(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
+fn change_object3(object: &mut Object) {
     //~^ HELP you might have meant to mutate
     let mut object2 = Object; //~ HELP consider changing this to be mutable
     *object = object2;
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
index 1fd222e0db1..5805afb3369 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![deny(unused_assignments, unused_variables)]
+#![deny(unused_assignments)]
 #![allow(unused_mut)]
 struct Object;
 
@@ -8,15 +8,15 @@ fn change_object(mut object: &Object) { //~ HELP you might have meant to mutate
    object = object2; //~ ERROR mismatched types
 }
 
-fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used
-   //~^ HELP you might have meant to mutate
+fn change_object2(mut object: &Object) {
+    //~^ HELP you might have meant to mutate
    let object2 = Object;
    object = &object2;
    //~^ ERROR `object2` does not live long enough
    //~| ERROR value assigned to `object` is never read
 }
 
-fn change_object3(mut object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
+fn change_object3(mut object: &mut Object) {
     //~^ HELP you might have meant to mutate
     let object2 = Object; //~ HELP consider changing this to be mutable
     object = &mut object2;
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
index 0330853d922..c2c7378f07a 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
@@ -23,7 +23,7 @@ LL |    object = &object2;
 note: the lint level is defined here
   --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:9
    |
-LL | #![deny(unused_assignments, unused_variables)]
+LL | #![deny(unused_assignments)]
    |         ^^^^^^^^^^^^^^^^^^
 help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
    |
@@ -33,19 +33,6 @@ LL |    let object2 = Object;
 LL ~    *object = object2;
    |
 
-error: variable `object` is assigned to, but never used
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:11:23
-   |
-LL | fn change_object2(mut object: &Object) {
-   |                       ^^^^^^
-   |
-   = note: consider using `_object` instead
-note: the lint level is defined here
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:29
-   |
-LL | #![deny(unused_assignments, unused_variables)]
-   |                             ^^^^^^^^^^^^^^^^
-
 error[E0597]: `object2` does not live long enough
   --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:14:13
    |
@@ -77,14 +64,6 @@ LL |     let object2 = Object;
 LL ~     *object = object2;
    |
 
-error: variable `object` is assigned to, but never used
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:19:23
-   |
-LL | fn change_object3(mut object: &mut Object) {
-   |                       ^^^^^^
-   |
-   = note: consider using `_object` instead
-
 error[E0596]: cannot borrow `object2` as mutable, as it is not declared as mutable
   --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:22:14
    |
@@ -96,7 +75,7 @@ help: consider changing this to be mutable
 LL |     let mut object2 = Object;
    |         +++
 
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0308, E0596, E0597.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.current.stderr b/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.current.stderr
new file mode 100644
index 00000000000..ccbe2d3593c
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.current.stderr
@@ -0,0 +1,29 @@
+error[E0277]: the trait bound `(): ReturnsSend` is not satisfied
+  --> $DIR/ice-issue-146191.rs:6:52
+   |
+LL | fn create_complex_future() -> impl Future<Output = impl ReturnsSend> {
+   |                                                    ^^^^^^^^^^^^^^^^ the trait `ReturnsSend` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/ice-issue-146191.rs:14:1
+   |
+LL | trait ReturnsSend {}
+   | ^^^^^^^^^^^^^^^^^
+note: required by a bound in an opaque type
+  --> $DIR/ice-issue-146191.rs:6:57
+   |
+LL | fn create_complex_future() -> impl Future<Output = impl ReturnsSend> {
+   |                                                         ^^^^^^^^^^^
+
+error[E0733]: recursion in an async block requires boxing
+  --> $DIR/ice-issue-146191.rs:8:5
+   |
+LL |     async { create_complex_future().await }
+   |     ^^^^^   ----------------------------- recursive call here
+   |
+   = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0733.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.next.stderr b/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.next.stderr
new file mode 100644
index 00000000000..e8b551c65fc
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.next.stderr
@@ -0,0 +1,17 @@
+error[E0282]: type annotations needed
+  --> $DIR/ice-issue-146191.rs:8:5
+   |
+LL |     async { create_complex_future().await }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+
+error[E0282]: type annotations needed
+  --> $DIR/ice-issue-146191.rs:8:5
+   |
+LL |     async { create_complex_future().await }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.rs b/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.rs
new file mode 100644
index 00000000000..356f7d01eb9
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/ice-issue-146191.rs
@@ -0,0 +1,15 @@
+//@ edition: 2024
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+fn create_complex_future() -> impl Future<Output = impl ReturnsSend> {
+    //[current]~^ ERROR the trait bound `(): ReturnsSend` is not satisfied
+    async { create_complex_future().await }
+    //[current]~^ ERROR recursion in an async block requires
+    //[next]~^^ ERROR type annotations needed
+    //[next]~| ERROR type annotations needed
+}
+
+trait ReturnsSend {}
+fn main() {}
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
index 45df8cc9c0c..10e8dbf41cc 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
@@ -1,14 +1,24 @@
-error[E0282]: type annotations needed
-  --> $DIR/recursive-in-exhaustiveness.rs:19:17
+error[E0282]: type annotations needed for `(_,)`
+  --> $DIR/recursive-in-exhaustiveness.rs:19:9
    |
 LL |     let (x,) = (build(x),);
-   |                 ^^^^^^^^ cannot infer type
+   |         ^^^^
+   |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+   |
+LL |     let (x,): (_,) = (build(x),);
+   |             ++++++
 
-error[E0282]: type annotations needed
-  --> $DIR/recursive-in-exhaustiveness.rs:29:17
+error[E0282]: type annotations needed for `((_,),)`
+  --> $DIR/recursive-in-exhaustiveness.rs:29:9
    |
 LL |     let (x,) = (build2(x),);
-   |                 ^^^^^^^^^ cannot infer type
+   |         ^^^^
+   |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+   |
+LL |     let (x,): ((_,),) = (build2(x),);
+   |             +++++++++
 
 error[E0282]: type annotations needed
   --> $DIR/recursive-in-exhaustiveness.rs:40:5
diff --git a/tests/ui/limits/huge-array-simple-64.stderr b/tests/ui/limits/huge-array-simple-64.full-debuginfo.stderr
index 46df288d4f7..8ce93ab1884 100644
--- a/tests/ui/limits/huge-array-simple-64.stderr
+++ b/tests/ui/limits/huge-array-simple-64.full-debuginfo.stderr
@@ -1,5 +1,5 @@
 error: values of the type `[u8; 2305843011361177600]` are too big for the target architecture
-  --> $DIR/huge-array-simple-64.rs:7:9
+  --> $DIR/huge-array-simple-64.rs:12:9
    |
 LL |     let _fat: [u8; (1<<61)+(1<<31)] =
    |         ^^^^
diff --git a/tests/ui/limits/huge-array-simple-64.no-debuginfo.stderr b/tests/ui/limits/huge-array-simple-64.no-debuginfo.stderr
new file mode 100644
index 00000000000..8ce93ab1884
--- /dev/null
+++ b/tests/ui/limits/huge-array-simple-64.no-debuginfo.stderr
@@ -0,0 +1,8 @@
+error: values of the type `[u8; 2305843011361177600]` are too big for the target architecture
+  --> $DIR/huge-array-simple-64.rs:12:9
+   |
+LL |     let _fat: [u8; (1<<61)+(1<<31)] =
+   |         ^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/limits/huge-array-simple-64.rs b/tests/ui/limits/huge-array-simple-64.rs
index d2838e0d41e..0c000940062 100644
--- a/tests/ui/limits/huge-array-simple-64.rs
+++ b/tests/ui/limits/huge-array-simple-64.rs
@@ -1,3 +1,8 @@
+// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2
+// NOTE: The .stderr for both revisions shall be identical.
+//@ revisions: no-debuginfo full-debuginfo
+//@[no-debuginfo] compile-flags: -Cdebuginfo=0
+//@[full-debuginfo] compile-flags: -Cdebuginfo=2
 //@ build-fail
 //@ ignore-32bit
 
diff --git a/tests/ui/limits/huge-array.stderr b/tests/ui/limits/huge-array.full-debuginfo.stderr
index ce0c0d650c2..0a9c8c67ce9 100644
--- a/tests/ui/limits/huge-array.stderr
+++ b/tests/ui/limits/huge-array.full-debuginfo.stderr
@@ -1,5 +1,5 @@
 error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the target architecture
-  --> $DIR/huge-array.rs:4:9
+  --> $DIR/huge-array.rs:9:9
    |
 LL |     let s: [T; 1518600000] = [t; 1518600000];
    |         ^
diff --git a/tests/ui/limits/huge-array.no-debuginfo.stderr b/tests/ui/limits/huge-array.no-debuginfo.stderr
new file mode 100644
index 00000000000..0a9c8c67ce9
--- /dev/null
+++ b/tests/ui/limits/huge-array.no-debuginfo.stderr
@@ -0,0 +1,8 @@
+error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the target architecture
+  --> $DIR/huge-array.rs:9:9
+   |
+LL |     let s: [T; 1518600000] = [t; 1518600000];
+   |         ^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/limits/huge-array.rs b/tests/ui/limits/huge-array.rs
index 97cfd1ff8fb..0cf59027694 100644
--- a/tests/ui/limits/huge-array.rs
+++ b/tests/ui/limits/huge-array.rs
@@ -1,3 +1,8 @@
+// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2
+// NOTE: The .stderr for both revisions shall be identical.
+//@ revisions: no-debuginfo full-debuginfo
+//@[no-debuginfo] compile-flags: -Cdebuginfo=0
+//@[full-debuginfo] compile-flags: -Cdebuginfo=2
 //@ build-fail
 
 fn generic<T: Copy>(t: T) {
diff --git a/tests/ui/limits/issue-15919-64.stderr b/tests/ui/limits/issue-15919-64.full-debuginfo.stderr
index cd443f2065b..54434675d25 100644
--- a/tests/ui/limits/issue-15919-64.stderr
+++ b/tests/ui/limits/issue-15919-64.full-debuginfo.stderr
@@ -1,5 +1,5 @@
 error: values of the type `[usize; usize::MAX]` are too big for the target architecture
-  --> $DIR/issue-15919-64.rs:5:9
+  --> $DIR/issue-15919-64.rs:10:9
    |
 LL |     let x = [0usize; 0xffff_ffff_ffff_ffff];
    |         ^
diff --git a/tests/ui/limits/issue-15919-64.no-debuginfo.stderr b/tests/ui/limits/issue-15919-64.no-debuginfo.stderr
new file mode 100644
index 00000000000..54434675d25
--- /dev/null
+++ b/tests/ui/limits/issue-15919-64.no-debuginfo.stderr
@@ -0,0 +1,8 @@
+error: values of the type `[usize; usize::MAX]` are too big for the target architecture
+  --> $DIR/issue-15919-64.rs:10:9
+   |
+LL |     let x = [0usize; 0xffff_ffff_ffff_ffff];
+   |         ^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/limits/issue-15919-64.rs b/tests/ui/limits/issue-15919-64.rs
index 7e6200882a9..c1eee1d95ba 100644
--- a/tests/ui/limits/issue-15919-64.rs
+++ b/tests/ui/limits/issue-15919-64.rs
@@ -1,3 +1,8 @@
+// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2
+// NOTE: The .stderr for both revisions shall be identical.
+//@ revisions: no-debuginfo full-debuginfo
+//@[no-debuginfo] compile-flags: -Cdebuginfo=0
+//@[full-debuginfo] compile-flags: -Cdebuginfo=2
 //@ build-fail
 //@ ignore-32bit
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs
index 0c78d799bad..f5f92db3b50 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs
+++ b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs
@@ -11,4 +11,4 @@ pub fn lib_main() {
     unsafe { f(42); }
 }
 
-//~? ERROR Error calling dlltool 'does_not_exist.exe': program not found
+//~? ERROR error calling dlltool 'does_not_exist.exe': program not found
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr
index 4bbad9b30a7..311d8c61589 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr
@@ -1,4 +1,4 @@
-error: Error calling dlltool 'does_not_exist.exe': program not found
+error: error calling dlltool 'does_not_exist.exe': program not found
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/linking/mixed-allocator-shim.rs b/tests/ui/linking/mixed-allocator-shim.rs
new file mode 100644
index 00000000000..e4f20a11ebb
--- /dev/null
+++ b/tests/ui/linking/mixed-allocator-shim.rs
@@ -0,0 +1,16 @@
+//@ build-pass
+//@ compile-flags: --crate-type staticlib,dylib -Zstaticlib-prefer-dynamic
+//@ no-prefer-dynamic
+//@ needs-crate-type: dylib
+
+// Test that compiling for multiple crate types in a single compilation with
+// mismatching allocator shim requirements doesn't result in the allocator shim
+// missing entirely.
+// In this particular test the dylib crate type will statically link libstd and
+// thus need an allocator shim, while the staticlib crate type will dynamically
+// link libstd and thus not need an allocator shim.
+// The -Zstaticlib-prefer-dynamic flag could be avoided by doing it the other
+// way around, but testing that the staticlib correctly has the allocator shim
+// in that case would require a run-make test instead.
+
+pub fn foo() {}
diff --git a/tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs b/tests/ui/lint/improper-ctypes/allow-phantomdata-in-ffi.rs
index a90159d2b58..a90159d2b58 100644
--- a/tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs
+++ b/tests/ui/lint/improper-ctypes/allow-phantomdata-in-ffi.rs
diff --git a/tests/ui/lint/lint-ctypes-113436-1.rs b/tests/ui/lint/improper-ctypes/lint-113436-1.rs
index 1ca59c6868d..1ca59c6868d 100644
--- a/tests/ui/lint/lint-ctypes-113436-1.rs
+++ b/tests/ui/lint/improper-ctypes/lint-113436-1.rs
diff --git a/tests/ui/lint/lint-ctypes-113436-1.stderr b/tests/ui/lint/improper-ctypes/lint-113436-1.stderr
index 7b63043f057..f01dc3b6e0d 100644
--- a/tests/ui/lint/lint-ctypes-113436-1.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-113436-1.stderr
@@ -1,5 +1,5 @@
 error: `extern` fn uses type `NotSafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-113436-1.rs:22:22
+  --> $DIR/lint-113436-1.rs:22:22
    |
 LL | extern "C" fn bar(x: Bar) -> Bar {
    |                      ^^^ not FFI-safe
@@ -7,18 +7,18 @@ LL | extern "C" fn bar(x: Bar) -> Bar {
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-113436-1.rs:13:1
+  --> $DIR/lint-113436-1.rs:13:1
    |
 LL | struct NotSafe(u32);
    | ^^^^^^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-113436-1.rs:1:9
+  --> $DIR/lint-113436-1.rs:1:9
    |
 LL | #![deny(improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `NotSafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-113436-1.rs:22:30
+  --> $DIR/lint-113436-1.rs:22:30
    |
 LL | extern "C" fn bar(x: Bar) -> Bar {
    |                              ^^^ not FFI-safe
@@ -26,7 +26,7 @@ LL | extern "C" fn bar(x: Bar) -> Bar {
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-113436-1.rs:13:1
+  --> $DIR/lint-113436-1.rs:13:1
    |
 LL | struct NotSafe(u32);
    | ^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-73249-2.rs b/tests/ui/lint/improper-ctypes/lint-73249-2.rs
index 31af0e3d381..31af0e3d381 100644
--- a/tests/ui/lint/lint-ctypes-73249-2.rs
+++ b/tests/ui/lint/improper-ctypes/lint-73249-2.rs
diff --git a/tests/ui/lint/lint-ctypes-73249-2.stderr b/tests/ui/lint/improper-ctypes/lint-73249-2.stderr
index 2d0dfe94f09..d6c1cec2bd6 100644
--- a/tests/ui/lint/lint-ctypes-73249-2.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-73249-2.stderr
@@ -1,12 +1,12 @@
 error: `extern` block uses type `Qux`, which is not FFI-safe
-  --> $DIR/lint-ctypes-73249-2.rs:27:21
+  --> $DIR/lint-73249-2.rs:27:21
    |
 LL |     fn lint_me() -> A<()>;
    |                     ^^^^^ not FFI-safe
    |
    = note: opaque types have no C equivalent
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-73249-2.rs:2:9
+  --> $DIR/lint-73249-2.rs:2:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-73249-3.rs b/tests/ui/lint/improper-ctypes/lint-73249-3.rs
index 8bdf536bf77..8bdf536bf77 100644
--- a/tests/ui/lint/lint-ctypes-73249-3.rs
+++ b/tests/ui/lint/improper-ctypes/lint-73249-3.rs
diff --git a/tests/ui/lint/lint-ctypes-73249-3.stderr b/tests/ui/lint/improper-ctypes/lint-73249-3.stderr
index e1a313a2906..ebc9eb5eb82 100644
--- a/tests/ui/lint/lint-ctypes-73249-3.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-73249-3.stderr
@@ -1,12 +1,12 @@
 error: `extern` block uses type `Qux`, which is not FFI-safe
-  --> $DIR/lint-ctypes-73249-3.rs:21:25
+  --> $DIR/lint-73249-3.rs:21:25
    |
 LL |     pub fn lint_me() -> A;
    |                         ^ not FFI-safe
    |
    = note: opaque types have no C equivalent
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-73249-3.rs:2:9
+  --> $DIR/lint-73249-3.rs:2:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-73249-5.rs b/tests/ui/lint/improper-ctypes/lint-73249-5.rs
index cc6da59950d..cc6da59950d 100644
--- a/tests/ui/lint/lint-ctypes-73249-5.rs
+++ b/tests/ui/lint/improper-ctypes/lint-73249-5.rs
diff --git a/tests/ui/lint/lint-ctypes-73249-5.stderr b/tests/ui/lint/improper-ctypes/lint-73249-5.stderr
index c4fa955de05..484927f57fe 100644
--- a/tests/ui/lint/lint-ctypes-73249-5.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-73249-5.stderr
@@ -1,12 +1,12 @@
 error: `extern` block uses type `Qux`, which is not FFI-safe
-  --> $DIR/lint-ctypes-73249-5.rs:21:25
+  --> $DIR/lint-73249-5.rs:21:25
    |
 LL |     pub fn lint_me() -> A;
    |                         ^ not FFI-safe
    |
    = note: opaque types have no C equivalent
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-73249-5.rs:2:9
+  --> $DIR/lint-73249-5.rs:2:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-73251-1.rs b/tests/ui/lint/improper-ctypes/lint-73251-1.rs
index 07ae05be69f..07ae05be69f 100644
--- a/tests/ui/lint/lint-ctypes-73251-1.rs
+++ b/tests/ui/lint/improper-ctypes/lint-73251-1.rs
diff --git a/tests/ui/lint/lint-ctypes-73251-1.stderr b/tests/ui/lint/improper-ctypes/lint-73251-1.stderr
index 675a9de51cd..749722f0e22 100644
--- a/tests/ui/lint/lint-ctypes-73251-1.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-73251-1.stderr
@@ -1,12 +1,12 @@
 error: `extern` block uses type `Qux`, which is not FFI-safe
-  --> $DIR/lint-ctypes-73251-1.rs:24:21
+  --> $DIR/lint-73251-1.rs:24:21
    |
 LL |     fn lint_me() -> <u32 as Foo>::Assoc;
    |                     ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: opaque types have no C equivalent
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-73251-1.rs:2:9
+  --> $DIR/lint-73251-1.rs:2:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-73251-2.rs b/tests/ui/lint/improper-ctypes/lint-73251-2.rs
index c47118672e0..c47118672e0 100644
--- a/tests/ui/lint/lint-ctypes-73251-2.rs
+++ b/tests/ui/lint/improper-ctypes/lint-73251-2.rs
diff --git a/tests/ui/lint/lint-ctypes-73251-2.stderr b/tests/ui/lint/improper-ctypes/lint-73251-2.stderr
index 634950b29ed..3770b7d789f 100644
--- a/tests/ui/lint/lint-ctypes-73251-2.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-73251-2.stderr
@@ -1,12 +1,12 @@
 error: `extern` block uses type `AliasA`, which is not FFI-safe
-  --> $DIR/lint-ctypes-73251-2.rs:38:21
+  --> $DIR/lint-73251-2.rs:38:21
    |
 LL |     fn lint_me() -> <AliasB as TraitB>::Assoc;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: opaque types have no C equivalent
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-73251-2.rs:2:9
+  --> $DIR/lint-73251-2.rs:2:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/improper-ctypes/lint-94223.rs
index ac24f61b0ac..ac24f61b0ac 100644
--- a/tests/ui/lint/lint-ctypes-94223.rs
+++ b/tests/ui/lint/improper-ctypes/lint-94223.rs
diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/improper-ctypes/lint-94223.stderr
index bd127cf6004..008debf8f01 100644
--- a/tests/ui/lint/lint-ctypes-94223.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-94223.stderr
@@ -1,5 +1,5 @@
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:4:15
+  --> $DIR/lint-94223.rs:4:15
    |
 LL | pub fn bad(f: extern "C" fn([u8])) {}
    |               ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -7,13 +7,13 @@ LL | pub fn bad(f: extern "C" fn([u8])) {}
    = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-94223.rs:2:9
+  --> $DIR/lint-94223.rs:2:9
    |
 LL | #![deny(improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:7:28
+  --> $DIR/lint-94223.rs:7:28
    |
 LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
    |                            ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -22,7 +22,7 @@ LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:7:49
+  --> $DIR/lint-94223.rs:7:49
    |
 LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
    |                                                 ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -31,7 +31,7 @@ LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:11:18
+  --> $DIR/lint-94223.rs:11:18
    |
 LL | struct BadStruct(extern "C" fn([u8]));
    |                  ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -40,7 +40,7 @@ LL | struct BadStruct(extern "C" fn([u8]));
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:15:7
+  --> $DIR/lint-94223.rs:15:7
    |
 LL |     A(extern "C" fn([u8])),
    |       ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -49,7 +49,7 @@ LL |     A(extern "C" fn([u8])),
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:20:7
+  --> $DIR/lint-94223.rs:20:7
    |
 LL |     A(extern "C" fn([u8])),
    |       ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -58,7 +58,7 @@ LL |     A(extern "C" fn([u8])),
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:24:12
+  --> $DIR/lint-94223.rs:24:12
    |
 LL | type Foo = extern "C" fn([u8]);
    |            ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -67,7 +67,7 @@ LL | type Foo = extern "C" fn([u8]);
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:31:20
+  --> $DIR/lint-94223.rs:31:20
    |
 LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -76,7 +76,7 @@ LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
    = note: enum has no representation hint
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:41:17
+  --> $DIR/lint-94223.rs:41:17
    |
 LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -84,13 +84,13 @@ LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:34:1
+  --> $DIR/lint-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:44:30
+  --> $DIR/lint-94223.rs:44:30
    |
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -98,13 +98,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:34:1
+  --> $DIR/lint-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:44:56
+  --> $DIR/lint-94223.rs:44:56
    |
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -112,13 +112,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:34:1
+  --> $DIR/lint-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
-  --> $DIR/lint-ctypes-94223.rs:48:22
+  --> $DIR/lint-94223.rs:48:22
    |
 LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -126,7 +126,7 @@ LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes-94223.rs:34:1
+  --> $DIR/lint-94223.rs:34:1
    |
 LL | pub struct FfiUnsafe;
    | ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/improper-ctypes/lint-cstr.rs
index b04decd0bca..b04decd0bca 100644
--- a/tests/ui/lint/lint-ctypes-cstr.rs
+++ b/tests/ui/lint/improper-ctypes/lint-cstr.rs
diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/improper-ctypes/lint-cstr.stderr
index 8957758d577..da263065843 100644
--- a/tests/ui/lint/lint-ctypes-cstr.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-cstr.stderr
@@ -1,5 +1,5 @@
 error: `extern` block uses type `CStr`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:7:21
+  --> $DIR/lint-cstr.rs:7:21
    |
 LL |     fn take_cstr(s: CStr);
    |                     ^^^^ not FFI-safe
@@ -7,13 +7,13 @@ LL |     fn take_cstr(s: CStr);
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-cstr.rs:2:9
+  --> $DIR/lint-cstr.rs:2:9
    |
 LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `CStr`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:10:25
+  --> $DIR/lint-cstr.rs:10:25
    |
 LL |     fn take_cstr_ref(s: &CStr);
    |                         ^^^^^ not FFI-safe
@@ -22,7 +22,7 @@ LL |     fn take_cstr_ref(s: &CStr);
    = note: `CStr`/`CString` do not have a guaranteed layout
 
 error: `extern` block uses type `CString`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:13:24
+  --> $DIR/lint-cstr.rs:13:24
    |
 LL |     fn take_cstring(s: CString);
    |                        ^^^^^^^ not FFI-safe
@@ -31,7 +31,7 @@ LL |     fn take_cstring(s: CString);
    = note: `CStr`/`CString` do not have a guaranteed layout
 
 error: `extern` block uses type `CString`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:16:28
+  --> $DIR/lint-cstr.rs:16:28
    |
 LL |     fn take_cstring_ref(s: &CString);
    |                            ^^^^^^^^ not FFI-safe
@@ -40,7 +40,7 @@ LL |     fn take_cstring_ref(s: &CString);
    = note: `CStr`/`CString` do not have a guaranteed layout
 
 error: `extern` block uses type `CString`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:20:43
+  --> $DIR/lint-cstr.rs:20:43
    |
 LL |     fn no_special_help_for_mut_cstring(s: *mut CString);
    |                                           ^^^^^^^^^^^^ not FFI-safe
@@ -49,7 +49,7 @@ LL |     fn no_special_help_for_mut_cstring(s: *mut CString);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `CString`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:24:47
+  --> $DIR/lint-cstr.rs:24:47
    |
 LL |     fn no_special_help_for_mut_cstring_ref(s: &mut CString);
    |                                               ^^^^^^^^^^^^ not FFI-safe
@@ -58,7 +58,7 @@ LL |     fn no_special_help_for_mut_cstring_ref(s: &mut CString);
    = note: this struct has unspecified layout
 
 error: `extern` fn uses type `CStr`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:29:37
+  --> $DIR/lint-cstr.rs:29:37
    |
 LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
    |                                     ^^^^^ not FFI-safe
@@ -66,13 +66,13 @@ LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-cstr.rs:2:26
+  --> $DIR/lint-cstr.rs:2:26
    |
 LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `CString`, which is not FFI-safe
-  --> $DIR/lint-ctypes-cstr.rs:32:36
+  --> $DIR/lint-cstr.rs:32:36
    |
 LL | extern "C" fn rust_take_cstring(s: CString) {}
    |                                    ^^^^^^^ not FFI-safe
diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/improper-ctypes/lint-ctypes.rs
index 47586c826ab..7dc06079fa3 100644
--- a/tests/ui/lint/lint-ctypes.rs
+++ b/tests/ui/lint/improper-ctypes/lint-ctypes.rs
@@ -52,7 +52,6 @@ extern "C" {
     pub fn str_type(p: &str); //~ ERROR: uses type `str`
     pub fn box_type(p: Box<u32>); //~ ERROR uses type `Box<u32>`
     pub fn opt_box_type(p: Option<Box<u32>>);
-    //~^ ERROR uses type `Option<Box<u32>>`
     pub fn char_type(p: char); //~ ERROR uses type `char`
     pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
     pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr
index 3fb36647d4f..6f8b951c53d 100644
--- a/tests/ui/lint/lint-ctypes.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr
@@ -67,17 +67,8 @@ LL |     pub fn box_type(p: Box<u32>);
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
-error: `extern` block uses type `Option<Box<u32>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:54:28
-   |
-LL |     pub fn opt_box_type(p: Option<Box<u32>>);
-   |                            ^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
-   = note: enum has no representation hint
-
 error: `extern` block uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:56:25
+  --> $DIR/lint-ctypes.rs:55:25
    |
 LL |     pub fn char_type(p: char);
    |                         ^^^^ not FFI-safe
@@ -86,7 +77,7 @@ LL |     pub fn char_type(p: char);
    = note: the `char` type has no C equivalent
 
 error: `extern` block uses type `dyn Bar`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:57:26
+  --> $DIR/lint-ctypes.rs:56:26
    |
 LL |     pub fn trait_type(p: &dyn Bar);
    |                          ^^^^^^^^ not FFI-safe
@@ -94,7 +85,7 @@ LL |     pub fn trait_type(p: &dyn Bar);
    = note: trait objects have no C equivalent
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:58:26
+  --> $DIR/lint-ctypes.rs:57:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
    |                          ^^^^^^^^^^ not FFI-safe
@@ -103,7 +94,7 @@ LL |     pub fn tuple_type(p: (i32, i32));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:59:27
+  --> $DIR/lint-ctypes.rs:58:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
    |                           ^^^^^^^ not FFI-safe
@@ -112,7 +103,7 @@ LL |     pub fn tuple_type2(p: I32Pair);
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:60:25
+  --> $DIR/lint-ctypes.rs:59:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
    |                         ^^^^^^^^ not FFI-safe
@@ -126,7 +117,7 @@ LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:61:33
+  --> $DIR/lint-ctypes.rs:60:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -139,7 +130,7 @@ LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:64:12
+  --> $DIR/lint-ctypes.rs:63:12
    |
 LL |         -> ::std::marker::PhantomData<bool>;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -147,7 +138,7 @@ LL |         -> ::std::marker::PhantomData<bool>;
    = note: composed only of `PhantomData`
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:65:23
+  --> $DIR/lint-ctypes.rs:64:23
    |
 LL |     pub fn fn_type(p: RustFn);
    |                       ^^^^^^ not FFI-safe
@@ -156,7 +147,7 @@ LL |     pub fn fn_type(p: RustFn);
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:66:24
+  --> $DIR/lint-ctypes.rs:65:24
    |
 LL |     pub fn fn_type2(p: fn());
    |                        ^^^^ not FFI-safe
@@ -165,7 +156,7 @@ LL |     pub fn fn_type2(p: fn());
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:67:28
+  --> $DIR/lint-ctypes.rs:66:28
    |
 LL |     pub fn fn_contained(p: RustBadRet);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -174,7 +165,7 @@ LL |     pub fn fn_contained(p: RustBadRet);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:68:31
+  --> $DIR/lint-ctypes.rs:67:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
    |                               ^^^^^^^^^^^^^^ not FFI-safe
@@ -183,7 +174,7 @@ LL |     pub fn transparent_str(p: TransparentStr);
    = note: string slices have no C equivalent
 
 error: `extern` block uses type `Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:69:30
+  --> $DIR/lint-ctypes.rs:68:30
    |
 LL |     pub fn transparent_fn(p: TransparentBadFn);
    |                              ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -192,7 +183,7 @@ LL |     pub fn transparent_fn(p: TransparentBadFn);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:70:27
+  --> $DIR/lint-ctypes.rs:69:27
    |
 LL |     pub fn raw_array(arr: [u8; 8]);
    |                           ^^^^^^^ not FFI-safe
@@ -201,7 +192,7 @@ LL |     pub fn raw_array(arr: [u8; 8]);
    = note: passing raw arrays by value is not FFI-safe
 
 error: `extern` block uses type `Option<UnsafeCell<extern "C" fn()>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:72:26
+  --> $DIR/lint-ctypes.rs:71:26
    |
 LL |     pub fn no_niche_a(a: Option<UnsafeCell<extern "C" fn()>>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -210,7 +201,7 @@ LL |     pub fn no_niche_a(a: Option<UnsafeCell<extern "C" fn()>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option<UnsafeCell<&i32>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:74:26
+  --> $DIR/lint-ctypes.rs:73:26
    |
 LL |     pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -218,5 +209,5 @@ LL |     pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
-error: aborting due to 22 previous errors
+error: aborting due to 21 previous errors
 
diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/improper-ctypes/lint-enum.rs
index f900f998d06..f900f998d06 100644
--- a/tests/ui/lint/lint-ctypes-enum.rs
+++ b/tests/ui/lint/improper-ctypes/lint-enum.rs
diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/improper-ctypes/lint-enum.stderr
index 40d22723309..35d1dcb87fd 100644
--- a/tests/ui/lint/lint-ctypes-enum.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-enum.stderr
@@ -1,5 +1,5 @@
 error: `extern` block uses type `U`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:82:14
+  --> $DIR/lint-enum.rs:82:14
    |
 LL |     fn uf(x: U);
    |              ^ not FFI-safe
@@ -7,18 +7,18 @@ LL |     fn uf(x: U);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 note: the type is defined here
-  --> $DIR/lint-ctypes-enum.rs:9:1
+  --> $DIR/lint-enum.rs:9:1
    |
 LL | enum U {
    | ^^^^^^
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-enum.rs:2:9
+  --> $DIR/lint-enum.rs:2:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `B`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:83:14
+  --> $DIR/lint-enum.rs:83:14
    |
 LL |     fn bf(x: B);
    |              ^ not FFI-safe
@@ -26,13 +26,13 @@ LL |     fn bf(x: B);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 note: the type is defined here
-  --> $DIR/lint-ctypes-enum.rs:12:1
+  --> $DIR/lint-enum.rs:12:1
    |
 LL | enum B {
    | ^^^^^^
 
 error: `extern` block uses type `T`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:84:14
+  --> $DIR/lint-enum.rs:84:14
    |
 LL |     fn tf(x: T);
    |              ^ not FFI-safe
@@ -40,13 +40,13 @@ LL |     fn tf(x: T);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 note: the type is defined here
-  --> $DIR/lint-ctypes-enum.rs:16:1
+  --> $DIR/lint-enum.rs:16:1
    |
 LL | enum T {
    | ^^^^^^
 
 error: `extern` block uses type `Option<TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:108:36
+  --> $DIR/lint-enum.rs:108:36
    |
 LL |     fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -55,7 +55,7 @@ LL |     fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option<Rust<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:110:28
+  --> $DIR/lint-enum.rs:110:28
    |
 LL |     fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -64,7 +64,7 @@ LL |     fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option<u8>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:111:21
+  --> $DIR/lint-enum.rs:111:21
    |
 LL |     fn option_u8(x: Option<u8>);
    |                     ^^^^^^^^^^ not FFI-safe
@@ -73,7 +73,7 @@ LL |     fn option_u8(x: Option<u8>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<TransparentUnion<NonZero<u8>>, ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:131:38
+  --> $DIR/lint-enum.rs:131:38
    |
 LL |     fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -82,7 +82,7 @@ LL |     fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Rust<NonZero<u8>>, ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:133:30
+  --> $DIR/lint-enum.rs:133:30
    |
 LL |     fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -91,7 +91,7 @@ LL |     fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:137:51
+  --> $DIR/lint-enum.rs:137:51
    |
 LL |     fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -100,7 +100,7 @@ LL |     fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>,
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:139:53
+  --> $DIR/lint-enum.rs:139:53
    |
 LL |     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -109,7 +109,7 @@ LL |     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:141:51
+  --> $DIR/lint-enum.rs:141:51
    |
 LL |     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -118,7 +118,7 @@ LL |     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:144:49
+  --> $DIR/lint-enum.rs:144:49
    |
 LL |     fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -127,7 +127,7 @@ LL |     fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:146:30
+  --> $DIR/lint-enum.rs:146:30
    |
 LL |     fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -136,7 +136,7 @@ LL |     fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:167:38
+  --> $DIR/lint-enum.rs:167:38
    |
 LL |     fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -145,7 +145,7 @@ LL |     fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:169:30
+  --> $DIR/lint-enum.rs:169:30
    |
 LL |     fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -154,7 +154,7 @@ LL |     fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:173:51
+  --> $DIR/lint-enum.rs:173:51
    |
 LL |     fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -163,7 +163,7 @@ LL |     fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:175:53
+  --> $DIR/lint-enum.rs:175:53
    |
 LL |     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -172,7 +172,7 @@ LL |     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:177:51
+  --> $DIR/lint-enum.rs:177:51
    |
 LL |     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -181,7 +181,7 @@ LL |     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:180:49
+  --> $DIR/lint-enum.rs:180:49
    |
 LL |     fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -190,7 +190,7 @@ LL |     fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:182:30
+  --> $DIR/lint-enum.rs:182:30
    |
 LL |     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -199,7 +199,7 @@ LL |     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:184:27
+  --> $DIR/lint-enum.rs:184:27
    |
 LL |     fn result_unit_t_e(x: Result<(), ()>);
    |                           ^^^^^^^^^^^^^^ not FFI-safe
diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/improper-ctypes/lint-fn.rs
index 0b84098e390..0b84098e390 100644
--- a/tests/ui/lint/lint-ctypes-fn.rs
+++ b/tests/ui/lint/improper-ctypes/lint-fn.rs
diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/improper-ctypes/lint-fn.stderr
index a19c04a63b5..34e3bd021b9 100644
--- a/tests/ui/lint/lint-ctypes-fn.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-fn.stderr
@@ -1,5 +1,5 @@
 error: `extern` fn uses type `[u32]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:70:33
+  --> $DIR/lint-fn.rs:70:33
    |
 LL | pub extern "C" fn slice_type(p: &[u32]) { }
    |                                 ^^^^^^ not FFI-safe
@@ -7,13 +7,13 @@ LL | pub extern "C" fn slice_type(p: &[u32]) { }
    = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-fn.rs:2:9
+  --> $DIR/lint-fn.rs:2:9
    |
 LL | #![deny(improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:73:31
+  --> $DIR/lint-fn.rs:73:31
    |
 LL | pub extern "C" fn str_type(p: &str) { }
    |                               ^^^^ not FFI-safe
@@ -22,7 +22,7 @@ LL | pub extern "C" fn str_type(p: &str) { }
    = note: string slices have no C equivalent
 
 error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:80:34
+  --> $DIR/lint-fn.rs:80:34
    |
 LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
    |                                  ^^^^^^^^^ not FFI-safe
@@ -30,7 +30,7 @@ LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
    = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `Box<str>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:83:35
+  --> $DIR/lint-fn.rs:83:35
    |
 LL | pub extern "C" fn boxed_string(p: Box<str>) { }
    |                                   ^^^^^^^^ not FFI-safe
@@ -38,7 +38,7 @@ LL | pub extern "C" fn boxed_string(p: Box<str>) { }
    = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:86:34
+  --> $DIR/lint-fn.rs:86:34
    |
 LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
    |                                  ^^^^^^^^^^^^^^ not FFI-safe
@@ -46,7 +46,7 @@ LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
    = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:89:32
+  --> $DIR/lint-fn.rs:89:32
    |
 LL | pub extern "C" fn char_type(p: char) { }
    |                                ^^^^ not FFI-safe
@@ -55,7 +55,7 @@ LL | pub extern "C" fn char_type(p: char) { }
    = note: the `char` type has no C equivalent
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:92:33
+  --> $DIR/lint-fn.rs:92:33
    |
 LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    |                                 ^^^^^^^^^^ not FFI-safe
@@ -64,7 +64,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:95:34
+  --> $DIR/lint-fn.rs:95:34
    |
 LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    |                                  ^^^^^^^ not FFI-safe
@@ -73,7 +73,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:98:32
+  --> $DIR/lint-fn.rs:98:32
    |
 LL | pub extern "C" fn zero_size(p: ZeroSize) { }
    |                                ^^^^^^^^ not FFI-safe
@@ -81,26 +81,26 @@ LL | pub extern "C" fn zero_size(p: ZeroSize) { }
    = help: consider adding a member to this struct
    = note: this struct has no fields
 note: the type is defined here
-  --> $DIR/lint-ctypes-fn.rs:25:1
+  --> $DIR/lint-fn.rs:25:1
    |
 LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:101:40
+  --> $DIR/lint-fn.rs:101:40
    |
 LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: composed only of `PhantomData`
 note: the type is defined here
-  --> $DIR/lint-ctypes-fn.rs:60:1
+  --> $DIR/lint-fn.rs:60:1
    |
 LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:104:51
+  --> $DIR/lint-fn.rs:104:51
    |
 LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    |                                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -108,7 +108,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:109:30
+  --> $DIR/lint-fn.rs:109:30
    |
 LL | pub extern "C" fn fn_type(p: RustFn) { }
    |                              ^^^^^^ not FFI-safe
@@ -117,7 +117,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:112:31
+  --> $DIR/lint-fn.rs:112:31
    |
 LL | pub extern "C" fn fn_type2(p: fn()) { }
    |                               ^^^^ not FFI-safe
@@ -126,7 +126,7 @@ LL | pub extern "C" fn fn_type2(p: fn()) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:117:38
+  --> $DIR/lint-fn.rs:117:38
    |
 LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    |                                      ^^^^^^^^^^^^^^ not FFI-safe
@@ -135,7 +135,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    = note: string slices have no C equivalent
 
 error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:169:43
+  --> $DIR/lint-fn.rs:169:43
    |
 LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    |                                           ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -143,7 +143,7 @@ LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:182:39
+  --> $DIR/lint-fn.rs:182:39
    |
 LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    |                                       ^^^^^^ not FFI-safe
@@ -152,7 +152,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    = note: this struct has unspecified layout
 
 error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:185:41
+  --> $DIR/lint-fn.rs:185:41
    |
 LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
    |                                         ^^^^^^ not FFI-safe
diff --git a/tests/ui/lint/lint-ctypes-non-recursion-limit.rs b/tests/ui/lint/improper-ctypes/lint-non-recursion-limit.rs
index 61e95dc5a46..61e95dc5a46 100644
--- a/tests/ui/lint/lint-ctypes-non-recursion-limit.rs
+++ b/tests/ui/lint/improper-ctypes/lint-non-recursion-limit.rs
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.rs
index ca08eb23a57..ca08eb23a57 100644
--- a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs
+++ b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.rs
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.stderr
index 74630469416..b17fb6bd614 100644
--- a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.stderr
@@ -1,5 +1,5 @@
 error: `extern` fn uses type `Option<&T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45
+  --> $DIR/lint-option-nonnull-unsized.rs:3:45
    |
 LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
    |                                             ^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -7,7 +7,7 @@ LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 note: the lint level is defined here
-  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9
+  --> $DIR/lint-option-nonnull-unsized.rs:1:9
    |
 LL | #![deny(improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-ctypes-113436.rs b/tests/ui/lint/improper-ctypes/mustpass-113436.rs
index d5acdc45f92..d5acdc45f92 100644
--- a/tests/ui/lint/lint-ctypes-113436.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-113436.rs
diff --git a/tests/ui/lint/lint-ctypes-113900.rs b/tests/ui/lint/improper-ctypes/mustpass-113900.rs
index 3dd196a4094..3dd196a4094 100644
--- a/tests/ui/lint/lint-ctypes-113900.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-113900.rs
diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs b/tests/ui/lint/improper-ctypes/mustpass-134060.rs
index b30be996736..b30be996736 100644
--- a/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-134060.rs
diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr b/tests/ui/lint/improper-ctypes/mustpass-134060.stderr
index f6ac9a92cd5..791b2f73709 100644
--- a/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr
+++ b/tests/ui/lint/improper-ctypes/mustpass-134060.stderr
@@ -1,5 +1,5 @@
 warning: `extern` fn uses type `()`, which is not FFI-safe
-  --> $DIR/improper_ctypes_definitions_ice_134060.rs:11:34
+  --> $DIR/mustpass-134060.rs:11:34
    |
 LL |     extern "C" fn foo_(&self, _: ()) -> i64 {
    |                                  ^^ not FFI-safe
diff --git a/tests/ui/lint/lint-ctypes-66202.rs b/tests/ui/lint/improper-ctypes/mustpass-66202.rs
index e4cfa54c8d8..e4cfa54c8d8 100644
--- a/tests/ui/lint/lint-ctypes-66202.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-66202.rs
diff --git a/tests/ui/lint/lint-ctypes-73249-1.rs b/tests/ui/lint/improper-ctypes/mustpass-73249-1.rs
index 0ca91ef294f..0ca91ef294f 100644
--- a/tests/ui/lint/lint-ctypes-73249-1.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-73249-1.rs
diff --git a/tests/ui/lint/lint-ctypes-73249-4.rs b/tests/ui/lint/improper-ctypes/mustpass-73249-4.rs
index 37099c1313a..37099c1313a 100644
--- a/tests/ui/lint/lint-ctypes-73249-4.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-73249-4.rs
diff --git a/tests/ui/lint/lint-ctypes-73249.rs b/tests/ui/lint/improper-ctypes/mustpass-73249.rs
index c5f2318ef0a..c5f2318ef0a 100644
--- a/tests/ui/lint/lint-ctypes-73249.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-73249.rs
diff --git a/tests/ui/lint/lint-ctypes-73251.rs b/tests/ui/lint/improper-ctypes/mustpass-73251.rs
index 15c1dfcaabf..15c1dfcaabf 100644
--- a/tests/ui/lint/lint-ctypes-73251.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-73251.rs
diff --git a/tests/ui/lint/lint-ctypes-73747.rs b/tests/ui/lint/improper-ctypes/mustpass-73747.rs
index a2562e3b421..a2562e3b421 100644
--- a/tests/ui/lint/lint-ctypes-73747.rs
+++ b/tests/ui/lint/improper-ctypes/mustpass-73747.rs
diff --git a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.rs
index 379c4132404..379c4132404 100644
--- a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs
+++ b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.rs
diff --git a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.stderr
index 5f0465bcf00..5f0465bcf00 100644
--- a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr
+++ b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.stderr
diff --git a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr
index b0c56003957..e5f2e65fd91 100644
--- a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr
+++ b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr
@@ -16,7 +16,7 @@ warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
 LL |         Foo => {}
-   |         ^^^ help: if this is intentional, prefix it with an underscore: `_Foo`
+   |         ^^^
    |
 note: the lint level is defined here
   --> $DIR/lint-uppercase-variables.rs:1:9
@@ -24,12 +24,29 @@ note: the lint level is defined here
 LL | #![warn(unused)]
    |         ^^^^^^
    = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Foo => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `Foo`
+   |
+LL |         foo::Foo::Foo => {}
+   |         ++++++++++
 
 warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:28:9
    |
 LL |     let Foo = foo::Foo::Foo;
-   |         ^^^ help: if this is intentional, prefix it with an underscore: `_Foo`
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |     let _Foo = foo::Foo::Foo;
+   |         +
+help: you might have meant to pattern match on the similarly named variant `Foo`
+   |
+LL |     let foo::Foo::Foo = foo::Foo::Foo;
+   |         ++++++++++
 
 error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
@@ -41,7 +58,16 @@ warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
    |
 LL |     fn in_param(Foo: foo::Foo) {}
-   |                 ^^^ help: if this is intentional, prefix it with an underscore: `_Foo`
+   |                 ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |     fn in_param(_Foo: foo::Foo) {}
+   |                 +
+help: you might have meant to pattern match on the similarly named variant `Foo`
+   |
+LL |     fn in_param(foo::Foo::Foo: foo::Foo) {}
+   |                 ++++++++++
 
 error: structure field `X` should have a snake case name
   --> $DIR/lint-uppercase-variables.rs:10:5
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr
index 203211d0d56..076a08ac6f2 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr
@@ -29,32 +29,6 @@ LL | #[no_link]
    | ^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:21:1
-   |
-LL | #![recursion_limit = "256"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:20:1
-   |
-LL | #![recursion_limit = "128"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:24:1
-   |
-LL | #![type_length_limit = "1"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:23:1
-   |
-LL | #![type_length_limit = "1048576"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:27:1
    |
 LL | #![no_std]
@@ -305,6 +279,32 @@ LL | #![crate_name = "unused_attr_duplicate"]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: unused attribute
+  --> $DIR/unused-attr-duplicate.rs:21:1
+   |
+LL | #![recursion_limit = "256"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/unused-attr-duplicate.rs:20:1
+   |
+LL | #![recursion_limit = "128"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+error: unused attribute
+  --> $DIR/unused-attr-duplicate.rs:24:1
+   |
+LL | #![type_length_limit = "1"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/unused-attr-duplicate.rs:23:1
+   |
+LL | #![type_length_limit = "1048576"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:29:1
    |
 LL | #![no_implicit_prelude]
diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.stderr b/tests/ui/lint/unused/unused-attr-macro-rules.stderr
index af64be8f6e9..0c6825026ed 100644
--- a/tests/ui/lint/unused/unused-attr-macro-rules.stderr
+++ b/tests/ui/lint/unused/unused-attr-macro-rules.stderr
@@ -1,19 +1,3 @@
-error: crate-level attribute should be an inner attribute
-  --> $DIR/unused-attr-macro-rules.rs:11:1
-   |
-LL | #[recursion_limit="1"]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/unused-attr-macro-rules.rs:1:9
-   |
-LL | #![deny(unused_attributes)]
-   |         ^^^^^^^^^^^^^^^^^
-help: add a `!`
-   |
-LL | #![recursion_limit="1"]
-   |  +
-
 error: `#[macro_use]` attribute cannot be used on macro defs
   --> $DIR/unused-attr-macro-rules.rs:7:1
    |
@@ -22,6 +6,11 @@ LL | #[macro_use]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[macro_use]` can be applied to modules, extern crates, and crates
+note: the lint level is defined here
+  --> $DIR/unused-attr-macro-rules.rs:1:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
 
 error: `#[path]` attribute cannot be used on macro defs
   --> $DIR/unused-attr-macro-rules.rs:9:1
@@ -32,5 +21,19 @@ LL | #[path="foo"]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[path]` can only be applied to modules
 
+error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
+  --> $DIR/unused-attr-macro-rules.rs:11:1
+   |
+LL | #[recursion_limit="1"]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: This attribute does not have an `!`, which means it is applied to this macro def
+  --> $DIR/unused-attr-macro-rules.rs:12:1
+   |
+LL | / macro_rules! foo {
+LL | |     () => {};
+LL | | }
+   | |_^
+
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/lto/issue-100772.rs b/tests/ui/lto/issue-100772.rs
index 29ec5b9bf96..9468e20894a 100644
--- a/tests/ui/lto/issue-100772.rs
+++ b/tests/ui/lto/issue-100772.rs
@@ -1,6 +1,6 @@
 //@ build-pass
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 //@ no-prefer-dynamic
 //@ only-x86_64-unknown-linux-gnu
 
diff --git a/tests/ui/lto/lto-global-allocator.rs b/tests/ui/lto/lto-global-allocator.rs
new file mode 100644
index 00000000000..03f11709c90
--- /dev/null
+++ b/tests/ui/lto/lto-global-allocator.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: --crate-type cdylib -C lto
+//@ build-pass
+//@ no-prefer-dynamic
+//@ needs-crate-type: cdylib
+
+use std::alloc::{GlobalAlloc, Layout};
+
+struct MyAllocator;
+
+unsafe impl GlobalAlloc for MyAllocator {
+    unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
+        todo!()
+    }
+
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+}
+
+#[global_allocator]
+static GLOBAL: MyAllocator = MyAllocator;
diff --git a/tests/ui/or-patterns/binding-typo-2.rs b/tests/ui/or-patterns/binding-typo-2.rs
new file mode 100644
index 00000000000..275b68a22e2
--- /dev/null
+++ b/tests/ui/or-patterns/binding-typo-2.rs
@@ -0,0 +1,122 @@
+// Issue #51976
+#![deny(unused_variables)] //~ NOTE: the lint level is defined here
+enum Lol {
+    Foo,
+    Bar,
+}
+const Bat: () = ();
+const Battery: () = ();
+struct Bay;
+
+fn foo(x: (Lol, Lol)) {
+    use Lol::*;
+    match &x {
+        (Foo, Bar) | (Ban, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named previously used binding `Bar`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        //~| ERROR: variable `Ban` is assigned to, but never used
+        //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
+        _ => {}
+    }
+    match &x {
+        (Foo, _) | (Ban, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named unit variant `Bar`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        //~| ERROR: variable `Ban` is assigned to, but never used
+        //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
+        _ => {}
+    }
+    match Some(42) {
+        Some(_) => {}
+        Non => {}
+        //~^ ERROR: unused variable: `Non`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| HELP: you might have meant to pattern match on the similarly named
+    }
+    match Some(42) {
+        Some(_) => {}
+        Non | None => {}
+        //~^ ERROR: unused variable: `Non`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| ERROR: variable `Non` is not bound in all patterns [E0408]
+        //~| NOTE: pattern doesn't bind `Non`
+        //~| NOTE: variable not in all patterns
+        //~| HELP: you might have meant to use the similarly named unit variant `None`
+        //~| HELP: you might have meant to pattern match on the similarly named
+    }
+    match Some(42) {
+        Non | Some(_) => {}
+        //~^ ERROR: unused variable: `Non`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| ERROR: variable `Non` is not bound in all patterns [E0408]
+        //~| NOTE: pattern doesn't bind `Non`
+        //~| NOTE: variable not in all patterns
+        //~| HELP: you might have meant to use the similarly named unit variant `None`
+        //~| HELP: you might have meant to pattern match on the similarly named
+    }
+}
+fn bar(x: (Lol, Lol)) {
+    use Lol::*;
+    use ::Bat;
+    use ::Bay;
+    match &x {
+        (Foo, _) | (Ban, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named unit variant `Bar`
+        //~| HELP: you might have meant to use the similarly named unit struct `Bay`
+        //~| HELP: you might have meant to use the similarly named constant `Bat`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        //~| ERROR: variable `Ban` is assigned to, but never used
+        //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
+        _ => {}
+    }
+}
+fn baz(x: (Lol, Lol)) {
+    use Lol::*;
+    use Bat;
+    match &x {
+        (Foo, _) | (Ban, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named unit variant `Bar`
+        //~| HELP: you might have meant to use the similarly named constant `Bat`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        //~| ERROR: variable `Ban` is assigned to, but never used
+        //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
+        _ => {}
+    }
+    match &x {
+        (Ban, _) => {}
+        //~^ ERROR: unused variable: `Ban`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| HELP: you might have meant to pattern match on the similarly named
+    }
+    match Bay {
+        Ban => {}
+        //~^ ERROR: unused variable: `Ban`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| HELP: you might have meant to pattern match on the similarly named
+    }
+    match () {
+        Batery => {}
+        //~^ ERROR: unused variable: `Batery`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| HELP: you might have meant to pattern match on the similarly named constant
+    }
+}
+
+fn main() {
+    use Lol::*;
+    foo((Foo, Bar));
+    bar((Foo, Bar));
+    baz((Foo, Bar));
+}
diff --git a/tests/ui/or-patterns/binding-typo-2.stderr b/tests/ui/or-patterns/binding-typo-2.stderr
new file mode 100644
index 00000000000..81ea6e6b1bc
--- /dev/null
+++ b/tests/ui/or-patterns/binding-typo-2.stderr
@@ -0,0 +1,254 @@
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:14:9
+   |
+LL |         (Foo, Bar) | (Ban, Foo) => {}
+   |         ^^^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
+   |
+help: you might have meant to use the similarly named previously used binding `Bar`
+   |
+LL -         (Foo, Bar) | (Ban, Foo) => {}
+LL +         (Foo, Bar) | (Bar, Foo) => {}
+   |
+
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:25:9
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |         ^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
+   |
+help: you might have meant to use the similarly named unit variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bar, Foo) => {}
+   |
+
+error[E0408]: variable `Non` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:44:15
+   |
+LL |         Non | None => {}
+   |         ---   ^^^^ pattern doesn't bind `Non`
+   |         |
+   |         variable not in all patterns
+   |
+help: you might have meant to use the similarly named unit variant `None`
+   |
+LL -         Non | None => {}
+LL +         core::option::Option::None | None => {}
+   |
+
+error[E0408]: variable `Non` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:54:15
+   |
+LL |         Non | Some(_) => {}
+   |         ---   ^^^^^^^ pattern doesn't bind `Non`
+   |         |
+   |         variable not in all patterns
+   |
+help: you might have meant to use the similarly named unit variant `None`
+   |
+LL -         Non | Some(_) => {}
+LL +         core::option::Option::None | Some(_) => {}
+   |
+
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:69:9
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |         ^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
+   |
+help: you might have meant to use the similarly named unit variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bar, Foo) => {}
+   |
+help: you might have meant to use the similarly named unit struct `Bay`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bay, Foo) => {}
+   |
+help: you might have meant to use the similarly named constant `Bat`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bat, Foo) => {}
+   |
+
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:86:9
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |         ^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
+   |
+help: you might have meant to use the similarly named unit variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bar, Foo) => {}
+   |
+help: you might have meant to use the similarly named constant `Bat`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bat, Foo) => {}
+   |
+
+error: variable `Ban` is assigned to, but never used
+  --> $DIR/binding-typo-2.rs:14:23
+   |
+LL |         (Foo, Bar) | (Ban, Foo) => {}
+   |                       ^^^
+   |
+   = note: consider using `_Ban` instead
+note: the lint level is defined here
+  --> $DIR/binding-typo-2.rs:2:9
+   |
+LL | #![deny(unused_variables)]
+   |         ^^^^^^^^^^^^^^^^
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, Bar) | (Ban, Foo) => {}
+LL +         (Foo, Bar) | (Lol::Bar, Foo) => {}
+   |
+
+error: variable `Ban` is assigned to, but never used
+  --> $DIR/binding-typo-2.rs:25:21
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |                     ^^^
+   |
+   = note: consider using `_Ban` instead
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Lol::Bar, Foo) => {}
+   |
+
+error: unused variable: `Non`
+  --> $DIR/binding-typo-2.rs:37:9
+   |
+LL |         Non => {}
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Non => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `None`
+   |
+LL -         Non => {}
+LL +         std::prelude::v1::None => {}
+   |
+
+error: unused variable: `Non`
+  --> $DIR/binding-typo-2.rs:44:9
+   |
+LL |         Non | None => {}
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Non | None => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `None`
+   |
+LL -         Non | None => {}
+LL +         std::prelude::v1::None | None => {}
+   |
+
+error: unused variable: `Non`
+  --> $DIR/binding-typo-2.rs:54:9
+   |
+LL |         Non | Some(_) => {}
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Non | Some(_) => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `None`
+   |
+LL -         Non | Some(_) => {}
+LL +         std::prelude::v1::None | Some(_) => {}
+   |
+
+error: variable `Ban` is assigned to, but never used
+  --> $DIR/binding-typo-2.rs:69:21
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |                     ^^^
+   |
+   = note: consider using `_Ban` instead
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Lol::Bar, Foo) => {}
+   |
+
+error: variable `Ban` is assigned to, but never used
+  --> $DIR/binding-typo-2.rs:86:21
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |                     ^^^
+   |
+   = note: consider using `_Ban` instead
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Lol::Bar, Foo) => {}
+   |
+
+error: unused variable: `Ban`
+  --> $DIR/binding-typo-2.rs:98:10
+   |
+LL |         (Ban, _) => {}
+   |          ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         (_Ban, _) => {}
+   |          +
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Ban, _) => {}
+LL +         (Lol::Bar, _) => {}
+   |
+
+error: unused variable: `Ban`
+  --> $DIR/binding-typo-2.rs:104:9
+   |
+LL |         Ban => {}
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Ban => {}
+   |         +
+help: you might have meant to pattern match on the similarly named struct `Bay`
+   |
+LL -         Ban => {}
+LL +         Bay => {}
+   |
+
+error: unused variable: `Batery`
+  --> $DIR/binding-typo-2.rs:110:9
+   |
+LL |         Batery => {}
+   |         ^^^^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Batery => {}
+   |         +
+help: you might have meant to pattern match on the similarly named constant `Battery`
+   |
+LL |         Battery => {}
+   |            +
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0408`.
diff --git a/tests/ui/or-patterns/binding-typo.fixed b/tests/ui/or-patterns/binding-typo.fixed
new file mode 100644
index 00000000000..f209ad644db
--- /dev/null
+++ b/tests/ui/or-patterns/binding-typo.fixed
@@ -0,0 +1,32 @@
+// Issue #51976
+//@ run-rustfix
+#![allow(unused_variables)] // allowed so we don't get overlapping suggestions
+enum Lol {
+    Foo,
+    Bar,
+}
+
+fn foo(x: (Lol, Lol)) {
+    use Lol::*;
+    match &x {
+        (Foo, Bar) | (Bar, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named previously used binding `Bar`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        _ => {}
+    }
+    match &x {
+        (Foo, _) | (Bar, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named unit variant `Bar`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        _ => {}
+    }
+}
+
+fn main() {
+    use Lol::*;
+    foo((Foo, Bar));
+}
diff --git a/tests/ui/or-patterns/binding-typo.rs b/tests/ui/or-patterns/binding-typo.rs
new file mode 100644
index 00000000000..6be9b801a0d
--- /dev/null
+++ b/tests/ui/or-patterns/binding-typo.rs
@@ -0,0 +1,32 @@
+// Issue #51976
+//@ run-rustfix
+#![allow(unused_variables)] // allowed so we don't get overlapping suggestions
+enum Lol {
+    Foo,
+    Bar,
+}
+
+fn foo(x: (Lol, Lol)) {
+    use Lol::*;
+    match &x {
+        (Foo, Bar) | (Ban, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named previously used binding `Bar`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        _ => {}
+    }
+    match &x {
+        (Foo, _) | (Ban, Foo) => {}
+        //~^ ERROR: variable `Ban` is not bound in all patterns
+        //~| HELP: you might have meant to use the similarly named unit variant `Bar`
+        //~| NOTE: pattern doesn't bind `Ban`
+        //~| NOTE: variable not in all patterns
+        _ => {}
+    }
+}
+
+fn main() {
+    use Lol::*;
+    foo((Foo, Bar));
+}
diff --git a/tests/ui/or-patterns/binding-typo.stderr b/tests/ui/or-patterns/binding-typo.stderr
new file mode 100644
index 00000000000..fb6d5f71209
--- /dev/null
+++ b/tests/ui/or-patterns/binding-typo.stderr
@@ -0,0 +1,31 @@
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo.rs:12:9
+   |
+LL |         (Foo, Bar) | (Ban, Foo) => {}
+   |         ^^^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
+   |
+help: you might have meant to use the similarly named previously used binding `Bar`
+   |
+LL -         (Foo, Bar) | (Ban, Foo) => {}
+LL +         (Foo, Bar) | (Bar, Foo) => {}
+   |
+
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo.rs:20:9
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |         ^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
+   |
+help: you might have meant to use the similarly named unit variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bar, Foo) => {}
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0408`.
diff --git a/tests/ui/or-patterns/missing-bindings.stderr b/tests/ui/or-patterns/missing-bindings.stderr
index 6288cc58913..636f7016647 100644
--- a/tests/ui/or-patterns/missing-bindings.stderr
+++ b/tests/ui/or-patterns/missing-bindings.stderr
@@ -86,6 +86,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |            ^^^^^^^     - variable not in all patterns
    |            |
    |            pattern doesn't bind `c`
+   |
+help: you might have meant to use the similarly named previously used binding `a`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(a), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:22
@@ -94,6 +100,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |              -       ^^^^ pattern doesn't bind `a`
    |              |
    |              variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(c, b) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `b` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:22
@@ -102,6 +114,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                 -    ^^^^ pattern doesn't bind `b`
    |                 |
    |                 variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, c) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `e` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:10
@@ -110,6 +128,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |          ^^^^^^^^^^^^^^^^^^^^     - variable not in all patterns
    |          |
    |          pattern doesn't bind `e`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(c), d) | B(c)) = Y;
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -118,6 +142,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |              -                  ^^^^ pattern doesn't bind `a`
    |              |
    |              variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(e, b) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `b` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -126,6 +156,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                 -               ^^^^ pattern doesn't bind `b`
    |                 |
    |                 variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, e) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `c` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -134,6 +170,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                        -        ^^^^ pattern doesn't bind `c`
    |                        |
    |                        variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(e), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `d` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -142,6 +184,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                            -    ^^^^ pattern doesn't bind `d`
    |                            |
    |                            variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(c), e) | B(e)) = Y;
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:63:29
@@ -158,6 +206,12 @@ LL |                     A(_, a) |
    |                     ^^^^^^^ pattern doesn't bind `b`
 LL |                     B(b),
    |                       - variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `a`
+   |
+LL -                     B(b),
+LL +                     B(a),
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:71:21
@@ -166,6 +220,12 @@ LL |                     A(_, a) |
    |                          - variable not in all patterns
 LL |                     B(b),
    |                     ^^^^ pattern doesn't bind `a`
+   |
+help: you might have meant to use the similarly named previously used binding `b`
+   |
+LL -                     A(_, a) |
+LL +                     A(_, b) |
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:74:17
@@ -202,6 +262,12 @@ LL |                       B(b),
 ...
 LL |               V3(c),
    |               ^^^^^ pattern doesn't bind `b`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -                     B(b),
+LL +                     B(c),
+   |
 
 error[E0408]: variable `c` is not bound in all patterns
   --> $DIR/missing-bindings.rs:59:13
@@ -223,6 +289,12 @@ LL | |             ) |
    | |_____________^ pattern doesn't bind `c`
 LL |               V3(c),
    |                  - variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `a`
+   |
+LL -             V3(c),
+LL +             V3(a),
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:78:13
@@ -235,6 +307,15 @@ LL |                     A(_, a) |
 ...
 LL |             V3(c),
    |             ^^^^^ pattern doesn't bind `a`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL ~                 B(Ok(a) | Err(c))
+LL |             ) |
+LL |             V2(
+LL |                 A(
+LL ~                     A(_, c) |
+   |
 
 error[E0170]: pattern binding `beta` is named the same as one of the variants of the type `check_handling_of_paths::bar::foo`
   --> $DIR/missing-bindings.rs:19:18
diff --git a/tests/ui/parser/expr-as-stmt-2.rs b/tests/ui/parser/expr-as-stmt-2.rs
index 3a18bdc3b73..4b1f62d8056 100644
--- a/tests/ui/parser/expr-as-stmt-2.rs
+++ b/tests/ui/parser/expr-as-stmt-2.rs
@@ -7,4 +7,25 @@ fn foo(a: Option<u32>, b: Option<u32>) -> bool {
     if let Some(y) = a { true } else { false }
 }
 
-fn main() {}
+fn bar() -> bool {
+    false
+}
+
+fn main() {
+    if true { true } else { false } && true;
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    if true { true } else { false } && if true { true } else { false };
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    if true { true } else { false } if true { true } else { false };
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    if true { bar() } else { bar() } && if true { bar() } else { bar() };
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    if true { bar() } else { bar() } if true { bar() } else { bar() };
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    let _ = if true { true } else { false } && true; // ok
+}
diff --git a/tests/ui/parser/expr-as-stmt-2.stderr b/tests/ui/parser/expr-as-stmt-2.stderr
index 2b6314c38ce..f9838ee0299 100644
--- a/tests/ui/parser/expr-as-stmt-2.stderr
+++ b/tests/ui/parser/expr-as-stmt-2.stderr
@@ -7,6 +7,10 @@ LL |     if let Some(x) = a { true } else { false }
    |     |                    expected `()`, found `bool`
    |     expected this to be `()`
    |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if let Some(x) = a { true } else { false })
+   |     +                                          +
 help: you might have meant to return this value
    |
 LL |     if let Some(x) = a { return true; } else { false }
@@ -21,6 +25,10 @@ LL |     if let Some(x) = a { true } else { false }
    |     |                                  expected `()`, found `bool`
    |     expected this to be `()`
    |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if let Some(x) = a { true } else { false })
+   |     +                                          +
 help: you might have meant to return this value
    |
 LL |     if let Some(x) = a { true } else { return false; }
@@ -41,6 +49,152 @@ help: parentheses are required to parse this as an expression
 LL |     (if let Some(x) = a { true } else { false })
    |     +                                          +
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:15:15
+   |
+LL |     if true { true } else { false } && true;
+   |     ----------^^^^-----------------
+   |     |         |
+   |     |         expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if true { true } else { false }) && true;
+   |     +                               +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:15:29
+   |
+LL |     if true { true } else { false } && true;
+   |     ------------------------^^^^^--
+   |     |                       |
+   |     |                       expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if true { true } else { false }) && true;
+   |     +                               +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:18:15
+   |
+LL |     if true { true } else { false } && if true { true } else { false };
+   |     ----------^^^^-----------------
+   |     |         |
+   |     |         expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if true { true } else { false }) && if true { true } else { false };
+   |     +                               +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:18:29
+   |
+LL |     if true { true } else { false } && if true { true } else { false };
+   |     ------------------------^^^^^--
+   |     |                       |
+   |     |                       expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if true { true } else { false }) && if true { true } else { false };
+   |     +                               +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:21:15
+   |
+LL |     if true { true } else { false } if true { true } else { false };
+   |     ----------^^^^-----------------
+   |     |         |
+   |     |         expected `()`, found `bool`
+   |     expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:21:29
+   |
+LL |     if true { true } else { false } if true { true } else { false };
+   |     ------------------------^^^^^--
+   |     |                       |
+   |     |                       expected `()`, found `bool`
+   |     expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:24:15
+   |
+LL |     if true { bar() } else { bar() } && if true { bar() } else { bar() };
+   |     ----------^^^^^-----------------
+   |     |         |
+   |     |         expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if true { bar() } else { bar() }) && if true { bar() } else { bar() };
+   |     +                                +
+help: consider using a semicolon here
+   |
+LL |     if true { bar() } else { bar() }; && if true { bar() } else { bar() };
+   |                                     +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:24:30
+   |
+LL |     if true { bar() } else { bar() } && if true { bar() } else { bar() };
+   |     -------------------------^^^^^--
+   |     |                        |
+   |     |                        expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (if true { bar() } else { bar() }) && if true { bar() } else { bar() };
+   |     +                                +
+help: consider using a semicolon here
+   |
+LL |     if true { bar() } else { bar() }; && if true { bar() } else { bar() };
+   |                                     +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:27:15
+   |
+LL |     if true { bar() } else { bar() } if true { bar() } else { bar() };
+   |     ----------^^^^^-----------------
+   |     |         |
+   |     |         expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: consider using a semicolon here
+   |
+LL |     if true { bar(); } else { bar() } if true { bar() } else { bar() };
+   |                    +
+help: consider using a semicolon here
+   |
+LL |     if true { bar() } else { bar() }; if true { bar() } else { bar() };
+   |                                     +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:27:30
+   |
+LL |     if true { bar() } else { bar() } if true { bar() } else { bar() };
+   |     -------------------------^^^^^--
+   |     |                        |
+   |     |                        expected `()`, found `bool`
+   |     expected this to be `()`
+   |
+help: consider using a semicolon here
+   |
+LL |     if true { bar() } else { bar(); } if true { bar() } else { bar() };
+   |                                   +
+help: consider using a semicolon here
+   |
+LL |     if true { bar() } else { bar() }; if true { bar() } else { bar() };
+   |                                     +
+
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/expr-as-stmt.fixed b/tests/ui/parser/expr-as-stmt.fixed
index 0a4d62a4a0c..bfae55047ed 100644
--- a/tests/ui/parser/expr-as-stmt.fixed
+++ b/tests/ui/parser/expr-as-stmt.fixed
@@ -66,7 +66,7 @@ fn asteroids() -> impl FnOnce() -> bool {
 
 // https://github.com/rust-lang/rust/issues/105179
 fn r#match() -> i32 {
-    (match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+`
+    ((match () { () => 1 })) + match () { () => 1 } //~ ERROR expected expression, found `+`
     //~^ ERROR mismatched types
 }
 
@@ -76,4 +76,13 @@ fn r#unsafe() -> i32 {
     //~^ ERROR mismatched types
 }
 
+// https://github.com/rust-lang/rust/issues/88727
+fn matches() -> bool {
+    (match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types
+    (match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types
+    //~^ ERROR expected `;`, found keyword `match`
+    (match () { _ => true }) && true; //~ ERROR mismatched types
+    ((match () { _ => true })) && true //~ ERROR mismatched types
+    //~^ ERROR mismatched types
+}
 fn main() {}
diff --git a/tests/ui/parser/expr-as-stmt.rs b/tests/ui/parser/expr-as-stmt.rs
index 99c85e65baa..94917432cb0 100644
--- a/tests/ui/parser/expr-as-stmt.rs
+++ b/tests/ui/parser/expr-as-stmt.rs
@@ -76,4 +76,13 @@ fn r#unsafe() -> i32 {
     //~^ ERROR mismatched types
 }
 
+// https://github.com/rust-lang/rust/issues/88727
+fn matches() -> bool {
+    match () { _ => true } && match () { _ => true }; //~ ERROR mismatched types
+    match () { _ => true } && match () { _ => true } //~ ERROR mismatched types
+    //~^ ERROR expected `;`, found keyword `match`
+    match () { _ => true } && true; //~ ERROR mismatched types
+    match () { _ => true } && true //~ ERROR mismatched types
+    //~^ ERROR mismatched types
+}
 fn main() {}
diff --git a/tests/ui/parser/expr-as-stmt.stderr b/tests/ui/parser/expr-as-stmt.stderr
index 577c3455a71..4681129baba 100644
--- a/tests/ui/parser/expr-as-stmt.stderr
+++ b/tests/ui/parser/expr-as-stmt.stderr
@@ -77,6 +77,15 @@ help: parentheses are required to parse this as an expression
 LL |     (unsafe { 1 }) + unsafe { 1 }
    |     +            +
 
+error: expected `;`, found keyword `match`
+  --> $DIR/expr-as-stmt.rs:82:53
+   |
+LL |     match () { _ => true } && match () { _ => true }
+   |                                                     ^ help: add `;` here
+LL |
+LL |     match () { _ => true } && true;
+   |     ----- unexpected token
+
 error[E0308]: mismatched types
   --> $DIR/expr-as-stmt.rs:64:7
    |
@@ -227,9 +236,12 @@ error[E0308]: mismatched types
   --> $DIR/expr-as-stmt.rs:69:5
    |
 LL |     match () { () => 1 } + match () { () => 1 }
-   |     ^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
-   |     |
-   |     expected `()`, found integer
+   |     ^^^^^^^^^^^^^^^^^^^^ expected `()`, found integer
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (match () { () => 1 }) + match () { () => 1 }
+   |     +                    +
 
 error[E0308]: mismatched types
   --> $DIR/expr-as-stmt.rs:75:14
@@ -242,7 +254,65 @@ help: you might have meant to return this value
 LL |     unsafe { return 1; } + unsafe { 1 }
    |              ++++++  +
 
-error: aborting due to 22 previous errors
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt.rs:81:5
+   |
+LL |     match () { _ => true } && match () { _ => true };
+   |     ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (match () { _ => true }) && match () { _ => true };
+   |     +                      +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt.rs:82:5
+   |
+LL |     match () { _ => true } && match () { _ => true }
+   |     ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (match () { _ => true }) && match () { _ => true }
+   |     +                      +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt.rs:84:5
+   |
+LL |     match () { _ => true } && true;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (match () { _ => true }) && true;
+   |     +                      +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt.rs:85:5
+   |
+LL |     match () { _ => true } && true
+   |     ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (match () { _ => true }) && true
+   |     +                      +
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt.rs:85:28
+   |
+LL | fn matches() -> bool {
+   |                 ---- expected `bool` because of return type
+...
+LL |     match () { _ => true } && true
+   |                            ^^^^^^^ expected `bool`, found `&&bool`
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (match () { _ => true }) && true
+   |     +                      +
+
+error: aborting due to 28 previous errors
 
 Some errors have detailed explanations: E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
index e7a0248cffa..243924e6c53 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
@@ -16,8 +16,7 @@ extern "C" fn f2_2(...) {}
 //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
 
 extern "C" fn f2_3(..., x: isize) {}
-//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-//~| ERROR `...` must be the last argument of a C-variadic function
+//~^ ERROR `...` must be the last argument of a C-variadic function
 
 extern "C" fn f3_1(x: isize, ...) {}
 //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
@@ -26,8 +25,7 @@ extern "C" fn f3_2(...) {}
 //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
 
 extern "C" fn f3_3(..., x: isize) {}
-//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-//~| ERROR `...` must be the last argument of a C-variadic function
+//~^ ERROR `...` must be the last argument of a C-variadic function
 
 const unsafe extern "C" fn f4_1(x: isize, ...) {}
 //~^ ERROR functions cannot be both `const` and C-variadic
@@ -77,9 +75,7 @@ trait T {
     fn t_f4(...);
     //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
     fn t_f5(..., x: isize) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-    //~| ERROR `...` must be the last argument of a C-variadic function
+    //~^ ERROR `...` must be the last argument of a C-variadic function
     fn t_f6(..., x: isize);
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-    //~| ERROR `...` must be the last argument of a C-variadic function
+    //~^ ERROR `...` must be the last argument of a C-variadic function
 }
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
index 5379045967a..5c55cc38b56 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -29,118 +29,103 @@ LL | extern "C" fn f2_3(..., x: isize) {}
    |                    ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20
-   |
-LL | extern "C" fn f2_3(..., x: isize) {}
-   |                    ^^^
-
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:22:30
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:21:30
    |
 LL | extern "C" fn f3_1(x: isize, ...) {}
    |                              ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:25:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:24:20
    |
 LL | extern "C" fn f3_2(...) {}
    |                    ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:28:20
-   |
-LL | extern "C" fn f3_3(..., x: isize) {}
-   |                    ^^^
-
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:28:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
    |
 LL | extern "C" fn f3_3(..., x: isize) {}
    |                    ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:32:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:1
    |
 LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
    | ^^^^^ `const` because of this             ^^^ C-variadic because of this
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:36:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:1
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    | ^^^^^ `const` because of this      ^^^ C-variadic because of this
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:36:36
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:41:26
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:26
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
    |                          ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:41:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:1
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
-   | ^^^^^                    ^^^            ^^^ C-variadic because of this
-   | |                        |
-   | |                        C-variadic because of this
-   | `const` because of this
+   | ^^^^^ `const` because of this           ^^^ C-variadic because of this
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:41:26
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:41
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
-   |                          ^^^            ^^^
+   |                                         ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:47:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:45:13
    |
 LL |     fn e_f2(..., x: isize);
    |             ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:54:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:52:23
    |
 LL |     fn i_f1(x: isize, ...) {}
    |                       ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:54:13
    |
 LL |     fn i_f2(...) {}
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13
    |
 LL |     fn i_f3(..., x: isize, ...) {}
    |             ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:56:28
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |             ^^^            ^^^
+   |                            ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
    |
 LL |     fn i_f4(..., x: isize, ...) {}
    |             ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |             ^^^            ^^^
+   |                            ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:5
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:5
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |     ^^^^^                   ^^^ C-variadic because of this
@@ -148,61 +133,49 @@ LL |     const fn i_f5(x: isize, ...) {}
    |     `const` because of this
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:29
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |                             ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:69:23
    |
 LL |     fn t_f1(x: isize, ...) {}
    |                       ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23
    |
 LL |     fn t_f2(x: isize, ...);
    |                       ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
    |
 LL |     fn t_f3(...) {}
    |             ^^^
 
 error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13
    |
 LL |     fn t_f4(...);
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13
-   |
-LL |     fn t_f5(..., x: isize) {}
-   |             ^^^
-
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13
    |
 LL |     fn t_f5(..., x: isize) {}
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13
-   |
-LL |     fn t_f6(..., x: isize);
-   |             ^^^
-
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13
    |
 LL |     fn t_f6(..., x: isize);
    |             ^^^
 
 error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:32:43
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:43
    |
 LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
    |                                           ^^^   - value is dropped here
@@ -210,7 +183,7 @@ LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
    |                                           the destructor for this type cannot be evaluated in constant functions
 
 error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:36:36
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    ^^^   - value is dropped here
@@ -218,13 +191,13 @@ LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    the destructor for this type cannot be evaluated in constant functions
 
 error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:29
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |                             ^^^   - value is dropped here
    |                             |
    |                             the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 36 previous errors
+error: aborting due to 32 previous errors
 
 For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/pattern/at-in-struct-patterns.rs b/tests/ui/pattern/at-in-struct-patterns.rs
index e8fad61f317..b0557220d05 100644
--- a/tests/ui/pattern/at-in-struct-patterns.rs
+++ b/tests/ui/pattern/at-in-struct-patterns.rs
@@ -5,7 +5,7 @@ struct Foo {
 
 fn main() {
     let foo = Foo { field1: 1, field2: 2 };
-    let Foo { var @ field1, .. } = foo; //~ ERROR Unexpected `@` in struct pattern
+    let Foo { var @ field1, .. } = foo; //~ ERROR unexpected `@` in struct pattern
     dbg!(var); //~ ERROR cannot find value `var` in this scope
     let Foo { field1: _, bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
     let Foo { bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
diff --git a/tests/ui/pattern/at-in-struct-patterns.stderr b/tests/ui/pattern/at-in-struct-patterns.stderr
index ff75edfe681..20832897ca5 100644
--- a/tests/ui/pattern/at-in-struct-patterns.stderr
+++ b/tests/ui/pattern/at-in-struct-patterns.stderr
@@ -1,4 +1,4 @@
-error: Unexpected `@` in struct pattern
+error: unexpected `@` in struct pattern
   --> $DIR/at-in-struct-patterns.rs:8:15
    |
 LL |     let Foo { var @ field1, .. } = foo;
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
index d76e60478a1..a5d9fd2b1a6 100644
--- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
@@ -5,6 +5,12 @@ LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |          ^^^^^^^^^^^^        - variable not in all patterns
    |          |
    |          pattern doesn't bind `y`
+   |
+help: you might have meant to use the similarly named previously used binding `x`
+   |
+LL -         ((Ok(x) if y) | (Err(y) if x),) => x && y,
+LL +         ((Ok(x) if y) | (Err(x) if x),) => x && y,
+   |
 
 error[E0408]: variable `x` is not bound in all patterns
   --> $DIR/name-resolution.rs:37:25
@@ -13,6 +19,12 @@ LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |              -          ^^^^^^^^^^^^^ pattern doesn't bind `x`
    |              |
    |              variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `y`
+   |
+LL -         ((Ok(x) if y) | (Err(y) if x),) => x && y,
+LL +         ((Ok(y) if y) | (Err(y) if x),) => x && y,
+   |
 
 error[E0408]: variable `x` is not bound in all patterns
   --> $DIR/name-resolution.rs:63:28
diff --git a/tests/ui/privacy/suggest-box-new.rs b/tests/ui/privacy/suggest-box-new.rs
index 7125285fc77..ff585387020 100644
--- a/tests/ui/privacy/suggest-box-new.rs
+++ b/tests/ui/privacy/suggest-box-new.rs
@@ -16,4 +16,7 @@ fn main() {
     let _ = std::collections::HashMap {};
     //~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields
     let _ = Box {}; //~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields
+
+    // test that we properly instantiate the parameter of `Box::<T>::new` with an inference variable
+    let _ = Box::<i32> {}; //~ ERROR cannot construct `Box<i32>` with struct literal syntax due to private fields
 }
diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr
index 2b48e9046bf..37b2989dcc1 100644
--- a/tests/ui/privacy/suggest-box-new.stderr
+++ b/tests/ui/privacy/suggest-box-new.stderr
@@ -118,13 +118,41 @@ LL +     let _ = Box::new_zeroed();
 LL -     let _ = Box {};
 LL +     let _ = Box::new_in(_, _);
    |
-   = and 12 other candidates
+   = and 13 other candidates
 help: consider using the `Default` trait
    |
 LL -     let _ = Box {};
 LL +     let _ = <Box as std::default::Default>::default();
    |
 
-error: aborting due to 4 previous errors
+error: cannot construct `Box<i32>` with struct literal syntax due to private fields
+  --> $DIR/suggest-box-new.rs:21:13
+   |
+LL |     let _ = Box::<i32> {};
+   |             ^^^^^^^^^^
+   |
+   = note: private fields `0` and `1` that were not provided
+help: you might have meant to use an associated function to build this type
+   |
+LL -     let _ = Box::<i32> {};
+LL +     let _ = Box::<i32>::new(_);
+   |
+LL -     let _ = Box::<i32> {};
+LL +     let _ = Box::<i32>::new_in(_, _);
+   |
+LL -     let _ = Box::<i32> {};
+LL +     let _ = Box::<i32>::into_inner(_);
+   |
+LL -     let _ = Box::<i32> {};
+LL +     let _ = Box::<i32>::write(_, _);
+   |
+   = and 4 other candidates
+help: consider using the `Default` trait
+   |
+LL -     let _ = Box::<i32> {};
+LL +     let _ = <Box::<i32> as std::default::Default>::default();
+   |
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/privacy/suggest-new-projection-ice.rs b/tests/ui/privacy/suggest-new-projection-ice.rs
new file mode 100644
index 00000000000..41ac27508e8
--- /dev/null
+++ b/tests/ui/privacy/suggest-new-projection-ice.rs
@@ -0,0 +1,19 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/146174>.
+//! Ensure that we don't ICE when an associated function returns an associated type.
+
+mod m {
+    pub trait Project {
+        type Assoc;
+    }
+    pub struct Foo {
+        _priv: (),
+    }
+    impl Foo {
+        fn new<T: Project>() -> T::Assoc {
+            todo!()
+        }
+    }
+}
+fn main() {
+    let _ = m::Foo {}; //~ ERROR: cannot construct `Foo`
+}
diff --git a/tests/ui/privacy/suggest-new-projection-ice.stderr b/tests/ui/privacy/suggest-new-projection-ice.stderr
new file mode 100644
index 00000000000..4700772096b
--- /dev/null
+++ b/tests/ui/privacy/suggest-new-projection-ice.stderr
@@ -0,0 +1,10 @@
+error: cannot construct `Foo` with struct literal syntax due to private fields
+  --> $DIR/suggest-new-projection-ice.rs:18:13
+   |
+LL |     let _ = m::Foo {};
+   |             ^^^^^^
+   |
+   = note: private field `_priv` that was not provided
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/recursion_limit/empty.rs b/tests/ui/recursion_limit/empty.rs
index 5987fa2f881..a901267d847 100644
--- a/tests/ui/recursion_limit/empty.rs
+++ b/tests/ui/recursion_limit/empty.rs
@@ -1,9 +1,7 @@
 // Test the parse error for an empty recursion_limit
 
-#![recursion_limit = ""] //~ ERROR `limit` must be a non-negative integer
-                         //~| NOTE `limit` must be a non-negative integer
-                         //~| ERROR `limit` must be a non-negative integer
-                         //~| NOTE `limit` must be a non-negative integer
-                         //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+#![recursion_limit = ""]
+//~^ ERROR `limit` must be a non-negative integer
+//~| NOTE `limit` must be a non-negative integer
 
 fn main() {}
diff --git a/tests/ui/recursion_limit/empty.stderr b/tests/ui/recursion_limit/empty.stderr
index 2f730677507..9afe9e6db56 100644
--- a/tests/ui/recursion_limit/empty.stderr
+++ b/tests/ui/recursion_limit/empty.stderr
@@ -6,15 +6,5 @@ LL | #![recursion_limit = ""]
    |                      |
    |                      `limit` must be a non-negative integer
 
-error: `limit` must be a non-negative integer
-  --> $DIR/empty.rs:3:1
-   |
-LL | #![recursion_limit = ""]
-   | ^^^^^^^^^^^^^^^^^^^^^--^
-   |                      |
-   |                      `limit` must be a non-negative integer
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/recursion_limit/invalid_digit.rs b/tests/ui/recursion_limit/invalid_digit.rs
index 79d8f3708ba..1d0e6a18227 100644
--- a/tests/ui/recursion_limit/invalid_digit.rs
+++ b/tests/ui/recursion_limit/invalid_digit.rs
@@ -1,8 +1,6 @@
 // Test the parse error for an invalid digit in recursion_limit
 
-#![recursion_limit = "-100"] //~ ERROR `limit` must be a non-negative integer
-                             //~| NOTE not a valid integer
-                             //~| ERROR `limit` must be a non-negative integer
-                             //~| NOTE not a valid integer
-                             //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+#![recursion_limit = "-100"]
+//~^ ERROR `limit` must be a non-negative integer
+//~| NOTE not a valid integer
 fn main() {}
diff --git a/tests/ui/recursion_limit/invalid_digit.stderr b/tests/ui/recursion_limit/invalid_digit.stderr
index 4fda3039032..9c2d1422df2 100644
--- a/tests/ui/recursion_limit/invalid_digit.stderr
+++ b/tests/ui/recursion_limit/invalid_digit.stderr
@@ -6,15 +6,5 @@ LL | #![recursion_limit = "-100"]
    |                      |
    |                      not a valid integer
 
-error: `limit` must be a non-negative integer
-  --> $DIR/invalid_digit.rs:3:1
-   |
-LL | #![recursion_limit = "-100"]
-   | ^^^^^^^^^^^^^^^^^^^^^------^
-   |                      |
-   |                      not a valid integer
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/recursion_limit/invalid_digit_type.stderr b/tests/ui/recursion_limit/invalid_digit_type.stderr
index a122262f1df..489e8bd82c2 100644
--- a/tests/ui/recursion_limit/invalid_digit_type.stderr
+++ b/tests/ui/recursion_limit/invalid_digit_type.stderr
@@ -1,10 +1,14 @@
-error: malformed `recursion_limit` attribute input
+error[E0539]: malformed `recursion_limit` attribute input
   --> $DIR/invalid_digit_type.rs:1:1
    |
 LL | #![recursion_limit = 123]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+   | ^^^^^^^^^^^^^^^^^^^^^---^
+   | |                    |
+   | |                    expected a string literal here
+   | help: must be of the form: `#![recursion_limit = "N"]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute>
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/recursion_limit/invalid_macro.rs b/tests/ui/recursion_limit/invalid_macro.rs
index 7db67a8d162..eae348523db 100644
--- a/tests/ui/recursion_limit/invalid_macro.rs
+++ b/tests/ui/recursion_limit/invalid_macro.rs
@@ -1,4 +1,4 @@
-#![recursion_limit = foo!()] //~ ERROR malformed `recursion_limit` attribute
+#![recursion_limit = foo!()] //~ ERROR attribute value must be a literal
 
 macro_rules! foo {
     () => {"128"};
diff --git a/tests/ui/recursion_limit/invalid_macro.stderr b/tests/ui/recursion_limit/invalid_macro.stderr
index b4dbc9fcb13..de1df3e9a35 100644
--- a/tests/ui/recursion_limit/invalid_macro.stderr
+++ b/tests/ui/recursion_limit/invalid_macro.stderr
@@ -1,10 +1,8 @@
-error: malformed `recursion_limit` attribute input
-  --> $DIR/invalid_macro.rs:1:1
+error: attribute value must be a literal
+  --> $DIR/invalid_macro.rs:1:22
    |
 LL | #![recursion_limit = foo!()]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute>
+   |                      ^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/recursion_limit/no-value.stderr b/tests/ui/recursion_limit/no-value.stderr
index 4a0ad04f271..eafc50bafb4 100644
--- a/tests/ui/recursion_limit/no-value.stderr
+++ b/tests/ui/recursion_limit/no-value.stderr
@@ -1,4 +1,4 @@
-error: malformed `recursion_limit` attribute input
+error[E0539]: malformed `recursion_limit` attribute input
   --> $DIR/no-value.rs:3:1
    |
 LL | #![recursion_limit]
@@ -8,3 +8,4 @@ LL | #![recursion_limit]
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/recursion_limit/overflow.rs b/tests/ui/recursion_limit/overflow.rs
index 7cd1d572e09..24cb8e286a8 100644
--- a/tests/ui/recursion_limit/overflow.rs
+++ b/tests/ui/recursion_limit/overflow.rs
@@ -3,8 +3,5 @@
 #![recursion_limit = "999999999999999999999999"]
 //~^ ERROR `limit` must be a non-negative integer
 //~| NOTE `limit` is too large
-//~| ERROR `limit` must be a non-negative integer
-//~| NOTE `limit` is too large
-//~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 fn main() {}
diff --git a/tests/ui/recursion_limit/overflow.stderr b/tests/ui/recursion_limit/overflow.stderr
index 6057177deb2..5a8548b7c7f 100644
--- a/tests/ui/recursion_limit/overflow.stderr
+++ b/tests/ui/recursion_limit/overflow.stderr
@@ -6,15 +6,5 @@ LL | #![recursion_limit = "999999999999999999999999"]
    |                      |
    |                      `limit` is too large
 
-error: `limit` must be a non-negative integer
-  --> $DIR/overflow.rs:3:1
-   |
-LL | #![recursion_limit = "999999999999999999999999"]
-   | ^^^^^^^^^^^^^^^^^^^^^--------------------------^
-   |                      |
-   |                      `limit` is too large
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/resolve/resolve-inconsistent-names.rs b/tests/ui/resolve/resolve-inconsistent-names.rs
index 9a40b20346c..96504720e83 100644
--- a/tests/ui/resolve/resolve-inconsistent-names.rs
+++ b/tests/ui/resolve/resolve-inconsistent-names.rs
@@ -10,8 +10,8 @@ pub mod m {
 fn main() {
     let y = 1;
     match y {
-       a | b => {} //~  ERROR variable `a` is not bound in all patterns
-                   //~| ERROR variable `b` is not bound in all patterns
+        a | b => {} //~  ERROR variable `a` is not bound in all patterns
+        //~| ERROR variable `b` is not bound in all patterns
     }
 
     let x = (E::A, E::B);
diff --git a/tests/ui/resolve/resolve-inconsistent-names.stderr b/tests/ui/resolve/resolve-inconsistent-names.stderr
index 5fac622eef2..d2333150961 100644
--- a/tests/ui/resolve/resolve-inconsistent-names.stderr
+++ b/tests/ui/resolve/resolve-inconsistent-names.stderr
@@ -1,18 +1,18 @@
 error[E0408]: variable `b` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:13:8
+  --> $DIR/resolve-inconsistent-names.rs:13:9
    |
-LL |        a | b => {}
-   |        ^   - variable not in all patterns
-   |        |
-   |        pattern doesn't bind `b`
+LL |         a | b => {}
+   |         ^   - variable not in all patterns
+   |         |
+   |         pattern doesn't bind `b`
 
 error[E0408]: variable `a` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:13:12
+  --> $DIR/resolve-inconsistent-names.rs:13:13
    |
-LL |        a | b => {}
-   |        -   ^ pattern doesn't bind `a`
-   |        |
-   |        variable not in all patterns
+LL |         a | b => {}
+   |         -   ^ pattern doesn't bind `a`
+   |         |
+   |         variable not in all patterns
 
 error[E0408]: variable `c` is not bound in all patterns
   --> $DIR/resolve-inconsistent-names.rs:19:9
diff --git a/tests/ui/sanitizer/address.rs b/tests/ui/sanitizer/address.rs
index 704d84764c1..1688f46c2d5 100644
--- a/tests/ui/sanitizer/address.rs
+++ b/tests/ui/sanitizer/address.rs
@@ -2,7 +2,7 @@
 //@ needs-sanitizer-address
 //@ ignore-cross-compile
 //
-//@ compile-flags: -Z sanitizer=address -O -g
+//@ compile-flags: -Z sanitizer=address -O -g -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail-or-crash
 //@ error-pattern: AddressSanitizer: stack-buffer-overflow
diff --git a/tests/ui/sanitizer/asan_odr_windows.rs b/tests/ui/sanitizer/asan_odr_windows.rs
index 28c24716761..b638d6eb969 100644
--- a/tests/ui/sanitizer/asan_odr_windows.rs
+++ b/tests/ui/sanitizer/asan_odr_windows.rs
@@ -2,7 +2,7 @@
 //! See <https://github.com/rust-lang/rust/issues/124390>.
 
 //@ run-pass
-//@ compile-flags:-Zsanitizer=address
+//@ compile-flags:-Zsanitizer=address -C unsafe-allow-abi-mismatch=sanitizer
 //@ aux-build: asan_odr_win-2.rs
 //@ only-windows-msvc
 //@ needs-sanitizer-support
diff --git a/tests/ui/sanitizer/badfree.rs b/tests/ui/sanitizer/badfree.rs
index 6b3aea7239c..b1b02649dcc 100644
--- a/tests/ui/sanitizer/badfree.rs
+++ b/tests/ui/sanitizer/badfree.rs
@@ -2,7 +2,7 @@
 //@ needs-sanitizer-address
 //@ ignore-cross-compile
 //
-//@ compile-flags: -Z sanitizer=address -O
+//@ compile-flags: -Z sanitizer=address -O -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail-or-crash
 //@ regex-error-pattern: AddressSanitizer: (SEGV|attempting free on address which was not malloc)
diff --git a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
index fad57198dfb..5de5e99f6d0 100644
--- a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
+++ b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
@@ -2,7 +2,7 @@
 // trait object type to fail, causing an ICE.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 //@ edition: 2021
 //@ no-prefer-dynamic
 //@ only-x86_64-unknown-linux-gnu
diff --git a/tests/ui/sanitizer/cfi/async-closures.rs b/tests/ui/sanitizer/cfi/async-closures.rs
index 9b099263000..621a0882c91 100644
--- a/tests/ui/sanitizer/cfi/async-closures.rs
+++ b/tests/ui/sanitizer/cfi/async-closures.rs
@@ -7,7 +7,7 @@
 //@ ignore-backends: gcc
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
index a881c6b92b2..310ce04c552 100644
--- a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
+++ b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
@@ -1,5 +1,5 @@
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 //@ no-prefer-dynamic
 //@ only-x86_64-unknown-linux-gnu
 //@ ignore-backends: gcc
diff --git a/tests/ui/sanitizer/cfi/closures.rs b/tests/ui/sanitizer/cfi/closures.rs
index fc9718faa28..7493dba4928 100644
--- a/tests/ui/sanitizer/cfi/closures.rs
+++ b/tests/ui/sanitizer/cfi/closures.rs
@@ -6,7 +6,7 @@
 //@ ignore-backends: gcc
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/cfi/complex-receiver.rs b/tests/ui/sanitizer/cfi/complex-receiver.rs
index aac44c33227..adacc0d6c5d 100644
--- a/tests/ui/sanitizer/cfi/complex-receiver.rs
+++ b/tests/ui/sanitizer/cfi/complex-receiver.rs
@@ -8,7 +8,7 @@
 //@ ignore-backends: gcc
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/cfi/coroutine.rs b/tests/ui/sanitizer/cfi/coroutine.rs
index 084a521f597..d85615b597d 100644
--- a/tests/ui/sanitizer/cfi/coroutine.rs
+++ b/tests/ui/sanitizer/cfi/coroutine.rs
@@ -8,6 +8,7 @@
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
 //@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/cfi/drop-in-place.rs b/tests/ui/sanitizer/cfi/drop-in-place.rs
index 160338a5b54..fe59d546312 100644
--- a/tests/ui/sanitizer/cfi/drop-in-place.rs
+++ b/tests/ui/sanitizer/cfi/drop-in-place.rs
@@ -5,6 +5,7 @@
 //@ ignore-backends: gcc
 //@ needs-sanitizer-cfi
 //@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
 //@ run-pass
 
 struct EmptyDrop;
diff --git a/tests/ui/sanitizer/cfi/drop-no-principal.rs b/tests/ui/sanitizer/cfi/drop-no-principal.rs
index e3a46fe9d75..4fb905eb51d 100644
--- a/tests/ui/sanitizer/cfi/drop-no-principal.rs
+++ b/tests/ui/sanitizer/cfi/drop-no-principal.rs
@@ -4,7 +4,7 @@
 // FIXME(#122848) Remove only-linux once OSX CFI binaries works
 //@ only-linux
 //@ ignore-backends: gcc
-//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
+//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 //@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0
 // FIXME(#118761) Should be run-pass once the labels on drop are compatible.
 // This test is being landed ahead of that to test that the compiler doesn't ICE while labeling the
diff --git a/tests/ui/sanitizer/cfi/fn-ptr.rs b/tests/ui/sanitizer/cfi/fn-ptr.rs
index d3209c62ddf..bdb8c7ceb32 100644
--- a/tests/ui/sanitizer/cfi/fn-ptr.rs
+++ b/tests/ui/sanitizer/cfi/fn-ptr.rs
@@ -7,6 +7,7 @@
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
 //@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C opt-level=0 -C codegen-units=1 -C lto
 //@ [cfi] compile-flags: -C prefer-dynamic=off
 //@ [cfi] compile-flags: -Z sanitizer=cfi
diff --git a/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs b/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs
index d46002c69fd..44cdcb250e7 100644
--- a/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs
+++ b/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs
@@ -4,6 +4,7 @@
 //@ needs-sanitizer-cfi
 //@ check-pass
 //@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
 
 #![feature(cfg_sanitizer_cfi)]
 
diff --git a/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs b/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs
index 24c2c2c13da..ce4e31eb69b 100644
--- a/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs
+++ b/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs
@@ -3,7 +3,7 @@
 //
 //@ needs-sanitizer-cfi
 //@ check-pass
-//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers
 
 #![feature(cfg_sanitizer_cfi)]
 
diff --git a/tests/ui/sanitizer/cfi/self-ref.rs b/tests/ui/sanitizer/cfi/self-ref.rs
index b93d49296b6..827610a2610 100644
--- a/tests/ui/sanitizer/cfi/self-ref.rs
+++ b/tests/ui/sanitizer/cfi/self-ref.rs
@@ -6,7 +6,7 @@
 //@ ignore-backends: gcc
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/cfi/sized-associated-ty.rs b/tests/ui/sanitizer/cfi/sized-associated-ty.rs
index eefc3e2e9db..da8c385c6fc 100644
--- a/tests/ui/sanitizer/cfi/sized-associated-ty.rs
+++ b/tests/ui/sanitizer/cfi/sized-associated-ty.rs
@@ -7,7 +7,7 @@
 //@ ignore-backends: gcc
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/cfi/supertraits.rs b/tests/ui/sanitizer/cfi/supertraits.rs
index f5a984b9583..b2782dff5d5 100644
--- a/tests/ui/sanitizer/cfi/supertraits.rs
+++ b/tests/ui/sanitizer/cfi/supertraits.rs
@@ -6,7 +6,7 @@
 //@ ignore-backends: gcc
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/cfi/transparent-has-regions.rs b/tests/ui/sanitizer/cfi/transparent-has-regions.rs
index b70e1ea1791..b82850133c1 100644
--- a/tests/ui/sanitizer/cfi/transparent-has-regions.rs
+++ b/tests/ui/sanitizer/cfi/transparent-has-regions.rs
@@ -1,5 +1,5 @@
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 //@ no-prefer-dynamic
 //@ only-x86_64-unknown-linux-gnu
 //@ build-pass
diff --git a/tests/ui/sanitizer/cfi/virtual-auto.rs b/tests/ui/sanitizer/cfi/virtual-auto.rs
index e6f2ebd4b2c..d3a715c079a 100644
--- a/tests/ui/sanitizer/cfi/virtual-auto.rs
+++ b/tests/ui/sanitizer/cfi/virtual-auto.rs
@@ -6,7 +6,7 @@
 //@ ignore-backends: gcc
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
-//@ compile-flags: -C target-feature=-crt-static
+//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
diff --git a/tests/ui/sanitizer/dataflow.rs b/tests/ui/sanitizer/dataflow.rs
index 658a9e48086..d99a1a6ac24 100644
--- a/tests/ui/sanitizer/dataflow.rs
+++ b/tests/ui/sanitizer/dataflow.rs
@@ -4,7 +4,7 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-dataflow
 //@ run-pass
-//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt
+//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt -C unsafe-allow-abi-mismatch=sanitizer
 
 use std::mem::size_of;
 use std::os::raw::{c_int, c_long, c_void};
diff --git a/tests/ui/sanitizer/hwaddress.rs b/tests/ui/sanitizer/hwaddress.rs
index e5939eb734b..05fcab17506 100644
--- a/tests/ui/sanitizer/hwaddress.rs
+++ b/tests/ui/sanitizer/hwaddress.rs
@@ -5,7 +5,7 @@
 //@ ignore-aarch64-unknown-linux-gnu
 //
 // FIXME(#83989): codegen-units=1 triggers linker errors on aarch64-gnu
-//@ compile-flags: -Z sanitizer=hwaddress -O -g -C codegen-units=16
+//@ compile-flags: -Z sanitizer=hwaddress -O -g -C codegen-units=16 -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail
 //@ error-pattern: HWAddressSanitizer: tag-mismatch
diff --git a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs
index 7d0c73c2841..be81c7bd0ca 100644
--- a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs
+++ b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs
@@ -2,7 +2,7 @@
 // encode_ty and caused the compiler to ICE.
 //
 //@ needs-sanitizer-cfi
-//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer
 //@ edition: 2021
 //@ no-prefer-dynamic
 //@ only-x86_64-unknown-linux-gnu
diff --git a/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs b/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs
index b1b7487fa2a..f7af2842ad6 100644
--- a/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs
+++ b/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs
@@ -2,7 +2,7 @@
 // was expecting array type lengths to be evaluated, this was causing an ICE.
 //
 //@ build-pass
-//@ compile-flags: -Ccodegen-units=1 -Clto -Zsanitizer=cfi -Ctarget-feature=-crt-static
+//@ compile-flags: -Ccodegen-units=1 -Clto -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer
 //@ needs-sanitizer-cfi
 
 #![crate_type = "lib"]
diff --git a/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs b/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs
index aa0c19db9a1..edeb1b0bf94 100644
--- a/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs
+++ b/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs
@@ -7,7 +7,7 @@
 //@ needs-sanitizer-address
 //@ ignore-cross-compile
 //
-//@ compile-flags: -Copt-level=0 -Zsanitizer=address
+//@ compile-flags: -Copt-level=0 -Zsanitizer=address -C unsafe-allow-abi-mismatch=sanitizer
 //@ run-pass
 
 pub struct Wrap {
diff --git a/tests/ui/sanitizer/kcfi-mangling.rs b/tests/ui/sanitizer/kcfi-mangling.rs
index ba36dc184ec..371f34ba72a 100644
--- a/tests/ui/sanitizer/kcfi-mangling.rs
+++ b/tests/ui/sanitizer/kcfi-mangling.rs
@@ -2,7 +2,7 @@
 
 //@ needs-sanitizer-kcfi
 //@ no-prefer-dynamic
-//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0
+//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0 -C unsafe-allow-abi-mismatch=sanitizer
 //@ build-pass
 //@ ignore-backends: gcc
 
diff --git a/tests/ui/sanitizer/leak.rs b/tests/ui/sanitizer/leak.rs
index 65915ec24b7..4ce3f7ab1b9 100644
--- a/tests/ui/sanitizer/leak.rs
+++ b/tests/ui/sanitizer/leak.rs
@@ -1,7 +1,7 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-leak
 //
-//@ compile-flags: -Z sanitizer=leak -O
+//@ compile-flags: -Z sanitizer=leak -O -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail
 //@ error-pattern: LeakSanitizer: detected memory leaks
diff --git a/tests/ui/sanitizer/memory-eager.rs b/tests/ui/sanitizer/memory-eager.rs
index 709299f87d4..9498336abb7 100644
--- a/tests/ui/sanitizer/memory-eager.rs
+++ b/tests/ui/sanitizer/memory-eager.rs
@@ -1,6 +1,8 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-memory
 //
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+//
 //@ revisions: unoptimized optimized
 //
 //@ [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
diff --git a/tests/ui/sanitizer/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs
index 96a4cd909c7..6ac41b178fe 100644
--- a/tests/ui/sanitizer/memory-passing.rs
+++ b/tests/ui/sanitizer/memory-passing.rs
@@ -1,6 +1,8 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-memory
 //
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+//
 //@ revisions: unoptimized optimized
 //
 //@ [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
diff --git a/tests/ui/sanitizer/memory.rs b/tests/ui/sanitizer/memory.rs
index a91fefe4d16..1566637acd2 100644
--- a/tests/ui/sanitizer/memory.rs
+++ b/tests/ui/sanitizer/memory.rs
@@ -1,6 +1,8 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-memory
 //
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+//
 //@ revisions: unoptimized optimized
 //
 //@ [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
diff --git a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs
index c1a2c2f26ac..b6656847427 100644
--- a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs
+++ b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs
@@ -6,6 +6,8 @@
 //@ needs-sanitizer-address
 //@ ignore-cross-compile
 //
+//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer
+//
 //@ no-prefer-dynamic
 //@ revisions: opt0 opt1
 //@ compile-flags: -Zsanitizer=address -Clto=thin
diff --git a/tests/ui/sanitizer/thread.rs b/tests/ui/sanitizer/thread.rs
index 9073124d1bd..8f72b1b41a8 100644
--- a/tests/ui/sanitizer/thread.rs
+++ b/tests/ui/sanitizer/thread.rs
@@ -13,7 +13,7 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-thread
 //
-//@ compile-flags: -Z sanitizer=thread -O
+//@ compile-flags: -Z sanitizer=thread -O -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail-or-crash
 //@ error-pattern: WARNING: ThreadSanitizer: data race
diff --git a/tests/ui/sanitizer/use-after-scope.rs b/tests/ui/sanitizer/use-after-scope.rs
index 106dc6466d6..1c477d0be14 100644
--- a/tests/ui/sanitizer/use-after-scope.rs
+++ b/tests/ui/sanitizer/use-after-scope.rs
@@ -2,7 +2,7 @@
 //@ needs-sanitizer-address
 //@ ignore-cross-compile
 //
-//@ compile-flags: -Zsanitizer=address
+//@ compile-flags: -Zsanitizer=address -C unsafe-allow-abi-mismatch=sanitizer
 //@ run-fail-or-crash
 //@ error-pattern: ERROR: AddressSanitizer: stack-use-after-scope
 
diff --git a/tests/ui/span/issue-39698.stderr b/tests/ui/span/issue-39698.stderr
index 73fcc5c8477..eb18969c3c0 100644
--- a/tests/ui/span/issue-39698.stderr
+++ b/tests/ui/span/issue-39698.stderr
@@ -7,6 +7,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |         |                      |    pattern doesn't bind `b`
    |         |                      variable not in all patterns
    |         pattern doesn't bind `b`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(a, d) | T::T2(d, c) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |
 
 error[E0408]: variable `c` is not bound in all patterns
   --> $DIR/issue-39698.rs:10:9
@@ -17,6 +23,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |         |             |                   variable not in all patterns
    |         |             pattern doesn't bind `c`
    |         pattern doesn't bind `c`
+   |
+help: you might have meant to use the similarly named previously used binding `d`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(a, d) | T::T2(d, b) | T::T3(d) | T::T4(a) => { println!("{:?}", a); }
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/issue-39698.rs:10:23
@@ -27,6 +39,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |               |       |             pattern doesn't bind `a`
    |               |       pattern doesn't bind `a`
    |               variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(c, d) | T::T2(d, b) | T::T3(c) | T::T4(c) => { println!("{:?}", a); }
+   |
 
 error[E0408]: variable `d` is not bound in all patterns
   --> $DIR/issue-39698.rs:10:37
@@ -37,6 +55,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |                  |          |       pattern doesn't bind `d`
    |                  |          variable not in all patterns
    |                  variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(a, c) | T::T2(c, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |
 
 error[E0381]: used binding `a` is possibly-uninitialized
   --> $DIR/issue-39698.rs:10:79
diff --git a/tests/ui/statics/mutable_memory_validation.stderr b/tests/ui/statics/mutable_memory_validation.stderr
index df36287cc69..1d6ba195fa2 100644
--- a/tests/ui/statics/mutable_memory_validation.stderr
+++ b/tests/ui/statics/mutable_memory_validation.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell`
 LL | const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } };
    | ^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr
index 1744162e6ce..9c8867a1771 100644
--- a/tests/ui/suggestions/multi-suggestion.ascii.stderr
+++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr
@@ -118,7 +118,7 @@ LL +     let _ = Box::new_zeroed();
 LL -     let _ = Box {};
 LL +     let _ = Box::new_in(_, _);
    |
-   = and 12 other candidates
+   = and 13 other candidates
 help: consider using the `Default` trait
    |
 LL -     let _ = Box {};
diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr
index 4835c263f19..4fdab51493e 100644
--- a/tests/ui/suggestions/multi-suggestion.unicode.stderr
+++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr
@@ -118,7 +118,7 @@ LL +     let _ = Box::new_zeroed();
 LL -     let _ = Box {};
 LL +     let _ = Box::new_in(_, _);

-   ╰ and 12 other candidates
+   ╰ and 13 other candidates
 help: consider using the `Default` trait
    ╭╴
 LL -     let _ = Box {};
diff --git a/tests/ui/target-feature/inline-always.aarch64.stderr b/tests/ui/target-feature/inline-always.aarch64.stderr
new file mode 100644
index 00000000000..a9ffb425c52
--- /dev/null
+++ b/tests/ui/target-feature/inline-always.aarch64.stderr
@@ -0,0 +1,60 @@
+warning: call to `#[inline(always)]`-annotated `target_feature_identity` requires the same target features to be inlined
+  --> $DIR/inline-always.rs:19:5
+   |
+LL |     target_feature_identity();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: function will not be inlined
+   = note: the following target features are on `target_feature_identity` but missing from `call_no_target_features`: neon, fp16
+note: `target_feature_identity` is defined here
+  --> $DIR/inline-always.rs:16:1
+   |
+LL | pub unsafe fn target_feature_identity() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(inline_always_mismatching_target_features)]` on by default
+help: add `#[target_feature]` attribute to `call_no_target_features`
+   |
+LL + #[target_feature(enable = "neon,fp16")]
+LL | unsafe fn call_no_target_features() {
+   |
+
+warning: call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined
+  --> $DIR/inline-always.rs:22:5
+   |
+LL |     multiple_target_features();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: function will not be inlined
+   = note: the following target features are on `multiple_target_features` but missing from `call_no_target_features`: fp16, sve, rdm
+note: `multiple_target_features` is defined here
+  --> $DIR/inline-always.rs:52:1
+   |
+LL | fn multiple_target_features() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add `#[target_feature]` attribute to `call_no_target_features`
+   |
+LL + #[target_feature(enable = "fp16,sve,rdm")]
+LL | unsafe fn call_no_target_features() {
+   |
+
+warning: call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined
+  --> $DIR/inline-always.rs:28:5
+   |
+LL |     multiple_target_features();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: function will not be inlined
+   = note: the following target features are on `multiple_target_features` but missing from `call_to_first_set`: rdm
+note: `multiple_target_features` is defined here
+  --> $DIR/inline-always.rs:52:1
+   |
+LL | fn multiple_target_features() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add `#[target_feature]` attribute to `call_to_first_set`
+   |
+LL + #[target_feature(enable = "rdm")]
+LL | unsafe fn call_to_first_set() {
+   |
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/target-feature/inline-always.rs b/tests/ui/target-feature/inline-always.rs
new file mode 100644
index 00000000000..dbf46537caa
--- /dev/null
+++ b/tests/ui/target-feature/inline-always.rs
@@ -0,0 +1,54 @@
+//@ add-core-stubs
+//@ build-pass
+//@ compile-flags: --crate-type=lib
+//@ revisions: aarch64
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: aarch64
+
+#![feature(no_core, target_feature_inline_always)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[inline(always)]
+#[target_feature(enable = "neon,fp16")]
+pub unsafe fn target_feature_identity() {}
+
+unsafe fn call_no_target_features() {
+    target_feature_identity();
+    //~^ WARNING call to `#[inline(always)]`-annotated `target_feature_identity` requires the same target features to be inlined [inline_always_mismatching_target_features]
+    global_feature_enabled();
+    multiple_target_features();
+    //~^ WARNING call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined [inline_always_mismatching_target_features]
+}
+
+#[target_feature(enable = "fp16,sve")]
+unsafe fn call_to_first_set() {
+    multiple_target_features();
+    //~^ WARNING call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined [inline_always_mismatching_target_features]
+}
+
+/* You can't have "fhm" without "fp16" */
+#[target_feature(enable = "fhm")]
+unsafe fn mismatching_features() {
+    target_feature_identity()
+}
+
+#[target_feature(enable = "fp16")]
+unsafe fn matching_target_features() {
+    target_feature_identity()
+}
+
+#[inline(always)]
+#[target_feature(enable = "neon")]
+unsafe fn global_feature_enabled() {
+
+}
+
+#[inline(always)]
+#[target_feature(enable = "fp16,sve")]
+#[target_feature(enable="rdm")]
+fn multiple_target_features() {
+
+ }
diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs
index b34a48aba26..a958700231a 100644
--- a/tests/ui/target-feature/invalid-attribute.rs
+++ b/tests/ui/target-feature/invalid-attribute.rs
@@ -61,6 +61,8 @@ trait Baz {}
 
 #[inline(always)]
 //~^ ERROR: cannot use `#[inline(always)]`
+//~| NOTE: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information
+//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 #[target_feature(enable = "sse2")]
 unsafe fn test() {}
 
diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr
index 7b75367b48c..d85bccce441 100644
--- a/tests/ui/target-feature/invalid-attribute.stderr
+++ b/tests/ui/target-feature/invalid-attribute.stderr
@@ -106,7 +106,7 @@ LL | #[target_feature(enable = "sse2")]
    = help: `#[target_feature]` can only be applied to functions
 
 error: `#[target_feature]` attribute cannot be used on statics
-  --> $DIR/invalid-attribute.rs:67:1
+  --> $DIR/invalid-attribute.rs:69:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -114,7 +114,7 @@ LL | #[target_feature(enable = "sse2")]
    = help: `#[target_feature]` can only be applied to functions
 
 error: `#[target_feature]` attribute cannot be used on trait impl blocks
-  --> $DIR/invalid-attribute.rs:71:1
+  --> $DIR/invalid-attribute.rs:73:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -122,7 +122,7 @@ LL | #[target_feature(enable = "sse2")]
    = help: `#[target_feature]` can only be applied to functions
 
 error: `#[target_feature]` attribute cannot be used on inherent impl blocks
-  --> $DIR/invalid-attribute.rs:77:1
+  --> $DIR/invalid-attribute.rs:79:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -130,7 +130,7 @@ LL | #[target_feature(enable = "sse2")]
    = help: `#[target_feature]` can only be applied to functions
 
 error: `#[target_feature]` attribute cannot be used on expressions
-  --> $DIR/invalid-attribute.rs:98:5
+  --> $DIR/invalid-attribute.rs:100:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -138,18 +138,22 @@ LL |     #[target_feature(enable = "sse2")]
    = help: `#[target_feature]` can only be applied to functions
 
 error: `#[target_feature]` attribute cannot be used on closures
-  --> $DIR/invalid-attribute.rs:104:5
+  --> $DIR/invalid-attribute.rs:106:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: `#[target_feature]` can be applied to methods and functions
 
-error: cannot use `#[inline(always)]` with `#[target_feature]`
+error[E0658]: cannot use `#[inline(always)]` with `#[target_feature]`
   --> $DIR/invalid-attribute.rs:62:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information
+   = help: add `#![feature(target_feature_inline_always)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: the feature named `foo` is not valid for this target
   --> $DIR/invalid-attribute.rs:20:18
@@ -158,7 +162,7 @@ LL | #[target_feature(enable = "foo")]
    |                  ^^^^^^^^^^^^^^ `foo` is not valid for this target
 
 error[E0046]: not all trait items implemented, missing: `foo`
-  --> $DIR/invalid-attribute.rs:73:1
+  --> $DIR/invalid-attribute.rs:75:1
    |
 LL | impl Quux for u8 {}
    | ^^^^^^^^^^^^^^^^ missing `foo` in implementation
@@ -167,7 +171,7 @@ LL |     fn foo();
    |     --------- `foo` from trait
 
 error: `#[target_feature(..)]` cannot be applied to safe trait method
-  --> $DIR/invalid-attribute.rs:87:5
+  --> $DIR/invalid-attribute.rs:89:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
@@ -176,13 +180,13 @@ LL |     fn foo() {}
    |     -------- not an `unsafe` function
 
 error[E0053]: method `foo` has an incompatible type for trait
-  --> $DIR/invalid-attribute.rs:90:5
+  --> $DIR/invalid-attribute.rs:92:5
    |
 LL |     fn foo() {}
    |     ^^^^^^^^ expected safe fn, found unsafe fn
    |
 note: type in trait
-  --> $DIR/invalid-attribute.rs:82:5
+  --> $DIR/invalid-attribute.rs:84:5
    |
 LL |     fn foo();
    |     ^^^^^^^^^
@@ -190,7 +194,7 @@ LL |     fn foo();
               found signature `#[target_features] fn()`
 
 error: the feature named `+sse2` is not valid for this target
-  --> $DIR/invalid-attribute.rs:109:18
+  --> $DIR/invalid-attribute.rs:111:18
    |
 LL | #[target_feature(enable = "+sse2")]
    |                  ^^^^^^^^^^^^^^^^ `+sse2` is not valid for this target
@@ -199,5 +203,5 @@ LL | #[target_feature(enable = "+sse2")]
 
 error: aborting due to 24 previous errors
 
-Some errors have detailed explanations: E0046, E0053, E0539.
+Some errors have detailed explanations: E0046, E0053, E0539, E0658.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/target_modifiers/auxiliary/kcfi-normalize-ints.rs b/tests/ui/target_modifiers/auxiliary/kcfi-normalize-ints.rs
new file mode 100644
index 00000000000..f97005a1450
--- /dev/null
+++ b/tests/ui/target_modifiers/auxiliary/kcfi-normalize-ints.rs
@@ -0,0 +1,7 @@
+//@ no-prefer-dynamic
+//@ needs-sanitizer-kcfi
+//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
+
+#![feature(no_core)]
+#![crate_type = "rlib"]
+#![no_core]
diff --git a/tests/ui/target_modifiers/auxiliary/no-sanitizers.rs b/tests/ui/target_modifiers/auxiliary/no-sanitizers.rs
new file mode 100644
index 00000000000..1d47ff6826d
--- /dev/null
+++ b/tests/ui/target_modifiers/auxiliary/no-sanitizers.rs
@@ -0,0 +1,6 @@
+//@ no-prefer-dynamic
+//@ compile-flags: -C panic=abort
+
+#![feature(no_core)]
+#![crate_type = "rlib"]
+#![no_core]
diff --git a/tests/ui/target_modifiers/auxiliary/safestack-and-kcfi.rs b/tests/ui/target_modifiers/auxiliary/safestack-and-kcfi.rs
new file mode 100644
index 00000000000..029744d2a1f
--- /dev/null
+++ b/tests/ui/target_modifiers/auxiliary/safestack-and-kcfi.rs
@@ -0,0 +1,10 @@
+//@ no-prefer-dynamic
+
+//@ needs-sanitizer-kcfi
+//@ needs-sanitizer-safestack
+
+//@ compile-flags: -C panic=abort -Zsanitizer=safestack,kcfi
+
+#![feature(no_core)]
+#![crate_type = "rlib"]
+#![no_core]
diff --git a/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.rs b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.rs
new file mode 100644
index 00000000000..cb9f701349a
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.rs
@@ -0,0 +1,18 @@
+// For kCFI, the helper flag -Zsanitizer-cfi-normalize-integers should also be a target modifier.
+
+//@ needs-sanitizer-kcfi
+//@ aux-build:kcfi-normalize-ints.rs
+//@ compile-flags: -Cpanic=abort
+
+//@ revisions: ok wrong_flag wrong_sanitizer
+//@[ok] compile-flags: -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
+//@[wrong_flag] compile-flags: -Zsanitizer=kcfi
+//@[ok] check-pass
+
+#![feature(no_core)]
+//[wrong_flag]~^ ERROR mixing `-Zsanitizer-cfi-normalize-integers` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints`
+//[wrong_sanitizer]~^^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints`
+#![crate_type = "rlib"]
+#![no_core]
+
+extern crate kcfi_normalize_ints;
diff --git a/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_flag.stderr b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_flag.stderr
new file mode 100644
index 00000000000..1db79b025e9
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_flag.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zsanitizer-cfi-normalize-integers` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints`
+  --> $DIR/sanitizer-kcfi-normalize-ints.rs:12:1
+   |
+LL | #![feature(no_core)]
+   | ^
+   |
+   = help: the `-Zsanitizer-cfi-normalize-integers` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: unset `-Zsanitizer-cfi-normalize-integers` in this crate is incompatible with `-Zsanitizer-cfi-normalize-integers=` in dependency `kcfi_normalize_ints`
+   = help: set `-Zsanitizer-cfi-normalize-integers=` in this crate or unset `-Zsanitizer-cfi-normalize-integers` in `kcfi_normalize_ints`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer-cfi-normalize-integers` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_sanitizer.stderr b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_sanitizer.stderr
new file mode 100644
index 00000000000..5b949c87350
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_sanitizer.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints`
+  --> $DIR/sanitizer-kcfi-normalize-ints.rs:12:1
+   |
+LL | #![feature(no_core)]
+   | ^
+   |
+   = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: unset `-Zsanitizer` in this crate is incompatible with `-Zsanitizer=kcfi` in dependency `kcfi_normalize_ints`
+   = help: set `-Zsanitizer=kcfi` in this crate or unset `-Zsanitizer` in `kcfi_normalize_ints`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/sanitizers-good-for-inconsistency.rs b/tests/ui/target_modifiers/sanitizers-good-for-inconsistency.rs
new file mode 100644
index 00000000000..abda7be9e40
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizers-good-for-inconsistency.rs
@@ -0,0 +1,19 @@
+// AddressSanitizer, LeakSanitizer are good to be inconsistent (they are not a target modifiers)
+
+//@ revisions: wrong_address_san wrong_leak_san
+
+//@[wrong_address_san] needs-sanitizer-address
+//@[wrong_leak_san] needs-sanitizer-leak
+
+//@ aux-build:no-sanitizers.rs
+//@ compile-flags: -Cpanic=abort -C target-feature=-crt-static
+
+//@[wrong_address_san] compile-flags: -Zsanitizer=address
+//@[wrong_leak_san] compile-flags: -Zsanitizer=leak
+//@ check-pass
+
+#![feature(no_core)]
+#![crate_type = "rlib"]
+#![no_core]
+
+extern crate no_sanitizers;
diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_both.stderr b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_both.stderr
new file mode 100644
index 00000000000..440a91c7707
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_both.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi`
+  --> $DIR/sanitizers-safestack-and-kcfi.rs:16:1
+   |
+LL | #![feature(no_core)]
+   | ^
+   |
+   = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: unset `-Zsanitizer` in this crate is incompatible with `-Zsanitizer=safestack,kcfi` in dependency `safestack_and_kcfi`
+   = help: set `-Zsanitizer=safestack,kcfi` in this crate or unset `-Zsanitizer` in `safestack_and_kcfi`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_kcfi.stderr b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_kcfi.stderr
new file mode 100644
index 00000000000..6cdd7facc37
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_kcfi.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi`
+  --> $DIR/sanitizers-safestack-and-kcfi.rs:16:1
+   |
+LL | #![feature(no_core)]
+   | ^
+   |
+   = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: `-Zsanitizer=safestack` in this crate is incompatible with `-Zsanitizer=safestack,kcfi` in dependency `safestack_and_kcfi`
+   = help: set `-Zsanitizer=safestack,kcfi` in this crate or `-Zsanitizer=safestack` in `safestack_and_kcfi`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_safestack.stderr b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_safestack.stderr
new file mode 100644
index 00000000000..ecfbcace39f
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_safestack.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi`
+  --> $DIR/sanitizers-safestack-and-kcfi.rs:16:1
+   |
+LL | #![feature(no_core)]
+   | ^
+   |
+   = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: `-Zsanitizer=kcfi` in this crate is incompatible with `-Zsanitizer=safestack,kcfi` in dependency `safestack_and_kcfi`
+   = help: set `-Zsanitizer=safestack,kcfi` in this crate or `-Zsanitizer=kcfi` in `safestack_and_kcfi`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.rs b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.rs
new file mode 100644
index 00000000000..6c3ceb7e910
--- /dev/null
+++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.rs
@@ -0,0 +1,23 @@
+//@ needs-sanitizer-kcfi
+//@ needs-sanitizer-safestack
+
+//@ aux-build:safestack-and-kcfi.rs
+//@ compile-flags: -Cpanic=abort
+
+//@ revisions: good good_reverted missed_safestack missed_kcfi missed_both
+//@[good] compile-flags: -Zsanitizer=safestack,kcfi
+//@[good_reverted] compile-flags: -Zsanitizer=kcfi,safestack
+//@[missed_safestack] compile-flags: -Zsanitizer=kcfi
+//@[missed_kcfi] compile-flags: -Zsanitizer=safestack
+// [missed_both] no additional compile-flags:
+//@[good] check-pass
+//@[good_reverted] check-pass
+
+#![feature(no_core)]
+//[missed_safestack]~^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi`
+//[missed_kcfi]~^^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi`
+//[missed_both]~^^^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi`
+#![crate_type = "rlib"]
+#![no_core]
+
+extern crate safestack_and_kcfi;
diff --git a/tests/ui/traits/bound/suggest-complex-bound-on-method.fixed b/tests/ui/traits/bound/suggest-complex-bound-on-method.fixed
new file mode 100644
index 00000000000..719835af0a9
--- /dev/null
+++ b/tests/ui/traits/bound/suggest-complex-bound-on-method.fixed
@@ -0,0 +1,23 @@
+//@ run-rustfix
+#![allow(dead_code)]
+struct Application;
+// https://github.com/rust-lang/rust/issues/144734
+trait Trait {
+    type Error: std::error::Error;
+
+    fn run(&self) -> Result<(), Self::Error>;
+}
+
+#[derive(Debug)]
+enum ApplicationError {
+    Quit,
+}
+
+impl Application {
+    fn thing<T: Trait>(&self, t: T) -> Result<(), ApplicationError> where ApplicationError: From<<T as Trait>::Error> {
+        t.run()?; //~ ERROR E0277
+        Ok(())
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/bound/suggest-complex-bound-on-method.rs b/tests/ui/traits/bound/suggest-complex-bound-on-method.rs
new file mode 100644
index 00000000000..39cec571242
--- /dev/null
+++ b/tests/ui/traits/bound/suggest-complex-bound-on-method.rs
@@ -0,0 +1,23 @@
+//@ run-rustfix
+#![allow(dead_code)]
+struct Application;
+// https://github.com/rust-lang/rust/issues/144734
+trait Trait {
+    type Error: std::error::Error;
+
+    fn run(&self) -> Result<(), Self::Error>;
+}
+
+#[derive(Debug)]
+enum ApplicationError {
+    Quit,
+}
+
+impl Application {
+    fn thing<T: Trait>(&self, t: T) -> Result<(), ApplicationError> {
+        t.run()?; //~ ERROR E0277
+        Ok(())
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/bound/suggest-complex-bound-on-method.stderr b/tests/ui/traits/bound/suggest-complex-bound-on-method.stderr
new file mode 100644
index 00000000000..ac45f049541
--- /dev/null
+++ b/tests/ui/traits/bound/suggest-complex-bound-on-method.stderr
@@ -0,0 +1,22 @@
+error[E0277]: `?` couldn't convert the error to `ApplicationError`
+  --> $DIR/suggest-complex-bound-on-method.rs:18:16
+   |
+LL |         t.run()?;
+   |           -----^ the trait `From<<T as Trait>::Error>` is not implemented for `ApplicationError`
+   |           |
+   |           this can't be annotated with `?` because it has type `Result<_, <T as Trait>::Error>`
+   |
+note: `ApplicationError` needs to implement `From<<T as Trait>::Error>`
+  --> $DIR/suggest-complex-bound-on-method.rs:12:1
+   |
+LL | enum ApplicationError {
+   | ^^^^^^^^^^^^^^^^^^^^^
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL |     fn thing<T: Trait>(&self, t: T) -> Result<(), ApplicationError> where ApplicationError: From<<T as Trait>::Error> {
+   |                                                                     +++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/constructor-const-fn.rs b/tests/ui/traits/const-traits/constructor-const-fn.rs
index 4a7bf531df2..af40ad94d1c 100644
--- a/tests/ui/traits/const-traits/constructor-const-fn.rs
+++ b/tests/ui/traits/const-traits/constructor-const-fn.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 //@ compile-flags: -Znext-solver
 #![feature(const_trait_impl)]
-const fn impls_fn<F: ~const Fn(u32) -> Foo>(_: &F) {}
+const fn impls_fn<F: [const] Fn(u32) -> Foo>(_: &F) {}
 
 struct Foo(u32);
 
diff --git a/tests/ui/traits/const-traits/reservation-impl-ice.rs b/tests/ui/traits/const-traits/reservation-impl-ice.rs
index 7fefb4ec543..3fbfe8c950d 100644
--- a/tests/ui/traits/const-traits/reservation-impl-ice.rs
+++ b/tests/ui/traits/const-traits/reservation-impl-ice.rs
@@ -1,7 +1,7 @@
 //@ compile-flags: -Znext-solver
 #![feature(const_convert, never_type, const_trait_impl)]
 
-const fn impls_from<T: ~const From<!>>() {}
+const fn impls_from<T: [const] From<!>>() {}
 
 const fn foo() {
     // This previously ICE'd when encountering the reservation impl
diff --git a/tests/ui/traits/const-traits/reservation-impl-ice.stderr b/tests/ui/traits/const-traits/reservation-impl-ice.stderr
index a3fdcbac69e..d30c014d63f 100644
--- a/tests/ui/traits/const-traits/reservation-impl-ice.stderr
+++ b/tests/ui/traits/const-traits/reservation-impl-ice.stderr
@@ -17,8 +17,8 @@ LL |     impls_from::<()>();
 note: required by a bound in `impls_from`
   --> $DIR/reservation-impl-ice.rs:4:24
    |
-LL | const fn impls_from<T: ~const From<!>>() {}
-   |                        ^^^^^^^^^^^^^^ required by this bound in `impls_from`
+LL | const fn impls_from<T: [const] From<!>>() {}
+   |                        ^^^^^^^^^^^^^^^ required by this bound in `impls_from`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-impl-trait/fallback.rs b/tests/ui/type-alias-impl-trait/fallback.rs
deleted file mode 100644
index a2f25acca0d..00000000000
--- a/tests/ui/type-alias-impl-trait/fallback.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Tests that we correctly handle opaque types being used opaquely,
-// even within their defining scope.
-//
-#![feature(type_alias_impl_trait)]
-
-type Foo = impl Copy;
-
-enum Wrapper<T> {
-    First(T),
-    Second,
-}
-
-// This method constrains `Foo` to be `bool`
-#[define_opaque(Foo)]
-fn constrained_foo() -> Foo {
-    true
-}
-
-// This method does not constrain `Foo`.
-// Per RFC 2071, function bodies may either
-// fully constrain an opaque type, or place no
-// constraints on it.
-#[define_opaque(Foo)]
-fn unconstrained_foo() -> Wrapper<Foo> {
-    Wrapper::Second
-    //~^ ERROR: type annotations needed
-}
-
-fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/fallback.stderr b/tests/ui/type-alias-impl-trait/fallback.stderr
deleted file mode 100644
index 1eb0afb13a8..00000000000
--- a/tests/ui/type-alias-impl-trait/fallback.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0283]: type annotations needed
-  --> $DIR/fallback.rs:25:5
-   |
-LL | fn unconstrained_foo() -> Wrapper<Foo> {
-   |                           ------------ type must be known at this point
-LL |     Wrapper::Second
-   |     ^^^^^^^^^^^^^^^
-   |     |
-   |     cannot infer type of the type parameter `T` declared on the enum `Wrapper`
-   |     return type was inferred to be `Wrapper<_>` here
-   |
-   = note: cannot satisfy `_: Copy`
-help: consider specifying the generic argument
-   |
-LL |     Wrapper::<T>::Second
-   |            +++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr
index b545cd75ddb..e19915a58a3 100644
--- a/tests/ui/type/pattern_types/validity.stderr
+++ b/tests/ui/type/pattern_types/validity.stderr
@@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something
 LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                HEX_DUMP
            }
@@ -34,7 +34,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some
 LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                HEX_DUMP
            }
@@ -45,7 +45,7 @@ error[E0080]: constructing invalid value at .0.0: encountered 0, but expected so
 LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) }));
    | ^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                HEX_DUMP
            }
@@ -66,7 +66,7 @@ error[E0080]: constructing invalid value: encountered 97, but expected something
 LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                HEX_DUMP
            }
@@ -77,7 +77,7 @@ error[E0080]: constructing invalid value: encountered 0xffffffff, but expected a
 LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
                HEX_DUMP
            }
diff --git a/tests/ui/type/type-name-basic.rs b/tests/ui/type/type-name-basic.rs
index 343bcae175a..2c41cb80aea 100644
--- a/tests/ui/type/type-name-basic.rs
+++ b/tests/ui/type/type-name-basic.rs
@@ -107,4 +107,19 @@ pub fn main() {
     }
     let a = Wrap(&()).get();
     v!(a, "type_name_basic::main::Wrap<&()>::get::Info");
+
+    struct Issue146249<T>(T);
+    impl Issue146249<Box<dyn FnOnce()>> {
+        pub fn bar(&self) {
+            let f = || {};
+            v!(
+                f,
+                "type_name_basic::main::Issue146249<\
+                    alloc::boxed::Box<dyn core::ops::function::FnOnce()>\
+                >::bar::{{closure}}"
+            );
+        }
+    }
+    let v: Issue146249<Box<dyn FnOnce()>> = Issue146249(Box::new(|| {}));
+    v.bar();
 }
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs
index 1a9652c1023..5a683884238 100644
--- a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs
@@ -9,6 +9,6 @@
 #[stable(feature = "a", since = "1.1.1")]
 #[unstable_feature_bound(feat_bar)]
 fn bar() {}
-//~^ ERROR Item annotated with `#[unstable_feature_bound]` should not be stable
+//~^ ERROR item annotated with `#[unstable_feature_bound]` should not be stable
 
 fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr
index 9cb6a181bef..9f07e63e454 100644
--- a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr
@@ -1,4 +1,4 @@
-error: Item annotated with `#[unstable_feature_bound]` should not be stable
+error: item annotated with `#[unstable_feature_bound]` should not be stable
   --> $DIR/unstable_feature_bound_incompatible_stability.rs:11:1
    |
 LL | fn bar() {}
diff --git a/triagebot.toml b/triagebot.toml
index cf2e95203fa..bf9bfee4306 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -235,7 +235,6 @@ trigger_files = [
     "src/etc/htmldocck.py",
     "src/tools/jsondocck",
     "src/tools/jsondoclint",
-    "src/tools/rustdoc-gui",
     "src/tools/rustdoc-js",
     "src/tools/rustdoc-themes",
 
@@ -336,6 +335,7 @@ trigger_files = [
     "tests/mir-opt",
     "tests/pretty",
     "tests/run-make",
+    "tests/run-make-cargo",
     "tests/ui",
     "tests/ui-fulldeps",
 ]
@@ -380,6 +380,7 @@ trigger_files = [
 [autolabel."O-apple"]
 trigger_files = [
     "library/std/src/os/darwin",
+    "library/std/src/sys/platform_version/darwin",
     "library/std/src/sys/sync/thread_parking/darwin.rs",
     "compiler/rustc_target/src/spec/base/apple",
 ]
@@ -592,6 +593,7 @@ trigger_files = [
 [autolabel."A-run-make"]
 trigger_files = [
     "tests/run-make",
+    "tests/run-make-cargo",
     "src/tools/run-make-support"
 ]
 
@@ -1306,6 +1308,21 @@ cc = ["@m-ou-se"]
 [mentions."compiler/rustc_ast_lowering/src/format.rs"]
 cc = ["@m-ou-se"]
 
+[mentions."#[miri::intrinsic_fallback_is_spec]"]
+type = "content"
+message = """
+`#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases,
+and explores the possible non-determinism of the intrinsic.
+"""
+cc = ["@rust-lang/miri"]
+[mentions."#[rustc_allow_const_fn_unstable"]
+type = "content"
+message = """
+`#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable
+implementation details on stable.
+"""
+cc = ["@rust-lang/wg-const-eval"]
+
 
 # ------------------------------------------------------------------------------
 # PR assignments
@@ -1527,6 +1544,7 @@ dep-bumps = [
 "/src/rustdoc-json-types" =                              ["rustdoc"]
 "/src/stage0" =                                          ["bootstrap"]
 "/tests/run-make" =                                      ["@jieyouxu"]
+"/tests/run-make-cargo" =                                ["@jieyouxu"]
 "/tests/rustdoc" =                                       ["rustdoc"]
 "/tests/rustdoc-gui" =                                   ["rustdoc"]
 "/tests/rustdoc-js-std" =                                ["rustdoc"]