about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/dependencies.yml10
-rw-r--r--.gitignore1
-rw-r--r--.reuse/dep5124
-rw-r--r--Cargo.lock364
-rw-r--r--Cargo.toml14
-rw-r--r--LICENSES/CC-BY-3.0.txt319
-rw-r--r--LICENSES/CC0-1.0.txt121
-rw-r--r--REUSE.toml170
-rw-r--r--compiler/rustc_ast_passes/messages.ftl3
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs7
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs16
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs11
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs15
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md2
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs1
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0771.md4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs16
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs93
-rw-r--r--compiler/rustc_feature/src/unstable.rs8
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl4
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs63
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs3
-rw-r--r--compiler/rustc_infer/messages.ftl392
-rw-r--r--compiler/rustc_infer/src/error_reporting/mod.rs1
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs1623
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs127
-rw-r--r--compiler/rustc_infer/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs204
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs1
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs83
-rw-r--r--compiler/rustc_middle/src/hooks/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs114
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs39
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs220
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs36
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs39
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs37
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/layout_test.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs8
-rw-r--r--compiler/rustc_resolve/src/late.rs6
-rw-r--r--compiler/rustc_span/src/symbol.rs5
-rw-r--r--compiler/rustc_target/src/target_features.rs12
-rw-r--r--compiler/rustc_trait_selection/messages.ftl391
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/mod.rs)120
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs (renamed from compiler/rustc_infer/src/infer/need_type_info.rs)51
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs)2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/note.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs)3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/region.rs)39
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs (renamed from compiler/rustc_infer/src/error_reporting/infer/suggest.rs)3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/mod.rs72
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs16
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs48
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs212
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs16
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs75
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs1639
-rw-r--r--compiler/rustc_trait_selection/src/errors/note_and_explain.rs (renamed from compiler/rustc_infer/src/errors/note_and_explain.rs)2
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs111
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_traits/src/codegen.rs2
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs2
-rw-r--r--library/alloc/src/boxed.rs83
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/marker.rs56
-rw-r--r--library/core/src/mem/transmutability.rs6
-rw-r--r--library/core/src/option.rs1
-rw-r--r--library/core/src/result.rs2
-rw-r--r--library/core/src/tuple.rs14
-rw-r--r--library/std/src/os/horizon/mod.rs1
-rw-r--r--library/std/src/os/horizon/raw.rs1
-rw-r--r--library/std/src/os/solid/io.rs1
-rw-r--r--library/std/src/os/solid/mod.rs1
-rw-r--r--library/std/src/sys/pal/solid/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/alloc.rs2
-rw-r--r--library/std/src/sys/pal/unix/net.rs5
-rw-r--r--library/std/src/sys/pal/unix/process/process_unsupported.rs1
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs85
-rw-r--r--library/std/src/sys/pal/windows/c.rs97
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt1
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs8
-rw-r--r--library/std/src/sys/pal/windows/net.rs112
-rw-r--r--library/std/src/sys/path/unsupported_backslash.rs1
-rw-r--r--library/std/src/sys/sync/mutex/itron.rs1
-rw-r--r--library/std/src/sys/sync/rwlock/solid.rs1
-rw-r--r--library/std/src/sys/thread_local/guard/windows.rs13
-rw-r--r--src/bootstrap/mk/Makefile.in1
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs33
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs77
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs59
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs7
-rw-r--r--src/bootstrap/src/core/builder.rs3
-rw-r--r--src/bootstrap/src/core/config/config.rs36
-rw-r--r--src/bootstrap/src/lib.rs2
-rw-r--r--src/bootstrap/src/utils/helpers.rs28
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in2
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt136
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile4
-rw-r--r--src/ci/github-actions/jobs.yml1
-rwxr-xr-xsrc/ci/run.sh2
-rw-r--r--src/doc/rustdoc/src/advanced-features.md27
-rw-r--r--src/etc/test-float-parse/Cargo.toml9
-rw-r--r--src/etc/test-float-parse/README.md55
-rwxr-xr-xsrc/etc/test-float-parse/runtests.py394
-rw-r--r--src/etc/test-float-parse/src/bin/few-ones.rs15
-rw-r--r--src/etc/test-float-parse/src/bin/huge-pow10.rs9
-rw-r--r--src/etc/test-float-parse/src/bin/long-fractions.rs15
-rw-r--r--src/etc/test-float-parse/src/bin/many-digits.rs25
-rw-r--r--src/etc/test-float-parse/src/bin/rand-f64.rs18
-rw-r--r--src/etc/test-float-parse/src/bin/short-decimals.rs17
-rw-r--r--src/etc/test-float-parse/src/bin/subnorm.rs11
-rw-r--r--src/etc/test-float-parse/src/bin/tiny-pow10.rs9
-rw-r--r--src/etc/test-float-parse/src/bin/u32-small.rs7
-rw-r--r--src/etc/test-float-parse/src/bin/u64-pow2.rs15
-rw-r--r--src/etc/test-float-parse/src/gen/exhaustive.rs43
-rw-r--r--src/etc/test-float-parse/src/gen/exponents.rs95
-rw-r--r--src/etc/test-float-parse/src/gen/fuzz.rs88
-rw-r--r--src/etc/test-float-parse/src/gen/integers.rs104
-rw-r--r--src/etc/test-float-parse/src/gen/long_fractions.rs58
-rw-r--r--src/etc/test-float-parse/src/gen/many_digits.rs84
-rw-r--r--src/etc/test-float-parse/src/gen/sparse.rs100
-rw-r--r--src/etc/test-float-parse/src/gen/spot_checks.rs101
-rw-r--r--src/etc/test-float-parse/src/gen/subnorm.rs103
-rw-r--r--src/etc/test-float-parse/src/lib.rs540
-rw-r--r--src/etc/test-float-parse/src/main.rs129
-rw-r--r--src/etc/test-float-parse/src/traits.rs202
-rw-r--r--src/etc/test-float-parse/src/ui.rs132
-rw-r--r--src/etc/test-float-parse/src/validate.rs364
-rw-r--r--src/etc/test-float-parse/src/validate/tests.rs149
-rw-r--r--src/librustdoc/html/render/print_item.rs21
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css6
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/build_helper/src/git.rs2
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs3
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics.stderr2
-rw-r--r--src/tools/collect-license-metadata/src/main.rs10
-rw-r--r--src/tools/collect-license-metadata/src/path_tree.rs52
-rw-r--r--src/tools/compiletest/src/common.rs10
-rw-r--r--src/tools/compiletest/src/runtest.rs268
-rw-r--r--src/tools/generate-copyright/src/main.rs38
-rw-r--r--src/tools/lint-docs/src/groups.rs1
-rw-r--r--src/tools/run-make-support/src/external_deps/llvm.rs2
-rw-r--r--src/tools/run-make-support/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/panic_context.rs1
-rw-r--r--src/tools/rustbook/Cargo.lock1762
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt18
-rw-r--r--src/tools/tidy/src/deps.rs10
-rw-r--r--src/version2
-rw-r--r--tests/codegen/generic-debug.rs1
-rw-r--r--tests/codegen/issues/issue-58881.rs1
-rw-r--r--tests/codegen/mainsubprogram.rs1
-rw-r--r--tests/codegen/mainsubprogramstart.rs1
-rw-r--r--tests/codegen/nounwind.rs1
-rw-r--r--tests/crashes/119299.rs25
-rw-r--r--tests/crashes/127009.rs11
-rw-r--r--tests/crashes/127351.rs17
-rw-r--r--tests/crashes/127353.rs18
-rw-r--r--tests/crashes/127628.rs14
-rw-r--r--tests/crashes/127643.rs18
-rw-r--r--tests/crashes/127676.rs8
-rw-r--r--tests/crashes/127737.rs21
-rw-r--r--tests/crashes/127742.rs11
-rw-r--r--tests/crashes/127880.rs5
-rw-r--r--tests/crashes/127916.rs16
-rw-r--r--tests/crashes/127972.rs6
-rw-r--r--tests/crashes/128016.rs10
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.rs2
-rw-r--r--tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/aggregate_copy.rs1
-rw-r--r--tests/mir-opt/issue_99325.rs2
-rw-r--r--tests/run-make/c-static-dylib/Makefile13
-rw-r--r--tests/run-make/c-static-dylib/rmake.rs20
-rw-r--r--tests/run-make/c-static-rlib/Makefile12
-rw-r--r--tests/run-make/c-static-rlib/rmake.rs17
-rw-r--r--tests/run-make/c-unwind-abi-catch-panic/Makefile10
-rw-r--r--tests/run-make/c-unwind-abi-catch-panic/rmake.rs18
-rw-r--r--tests/run-make/compiler-lookup-paths-2/Makefile11
-rw-r--r--tests/run-make/compiler-lookup-paths-2/rmake.rs20
-rw-r--r--tests/run-make/extern-fn-generic/Makefile7
-rw-r--r--tests/run-make/extern-fn-generic/rmake.rs16
-rw-r--r--tests/run-make/extern-fn-with-union/Makefile7
-rw-r--r--tests/run-make/extern-fn-with-union/rmake.rs16
-rw-r--r--tests/run-make/invalid-tmpdir-env-var/foo.rs (renamed from tests/run-make/issue-14698/foo.rs)0
-rw-r--r--tests/run-make/invalid-tmpdir-env-var/rmake.rs20
-rw-r--r--tests/run-make/issue-107094/Makefile7
-rw-r--r--tests/run-make/issue-14698/Makefile4
-rw-r--r--tests/run-make/issue-28595/Makefile7
-rw-r--r--tests/run-make/issue-33329/Makefile5
-rw-r--r--tests/run-make/issue-33329/main.rs1
-rw-r--r--tests/run-make/issue-97463-abi-param-passing/Makefile15
-rw-r--r--tests/run-make/linkage-attr-on-static/Makefile6
-rw-r--r--tests/run-make/linkage-attr-on-static/rmake.rs15
-rw-r--r--tests/run-make/lto-no-link-whole-rlib/Makefile9
-rw-r--r--tests/run-make/lto-no-link-whole-rlib/rmake.rs18
-rw-r--r--tests/run-make/native-lib-load-order/a.c (renamed from tests/run-make/issue-28595/a.c)0
-rw-r--r--tests/run-make/native-lib-load-order/a.rs (renamed from tests/run-make/issue-28595/a.rs)0
-rw-r--r--tests/run-make/native-lib-load-order/b.c (renamed from tests/run-make/issue-28595/b.c)0
-rw-r--r--tests/run-make/native-lib-load-order/b.rs (renamed from tests/run-make/issue-28595/b.rs)0
-rw-r--r--tests/run-make/native-lib-load-order/rmake.rs16
-rw-r--r--tests/run-make/pass-non-c-like-enum-to-c/Makefile6
-rw-r--r--tests/run-make/pass-non-c-like-enum-to-c/rmake.rs19
-rw-r--r--tests/run-make/return-non-c-like-enum-from-c/Makefile6
-rw-r--r--tests/run-make/return-non-c-like-enum-from-c/rmake.rs17
-rw-r--r--tests/run-make/rlib-format-packed-bundled-libs-3/Makefile35
-rw-r--r--tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs84
-rw-r--r--tests/run-make/staticlib-blank-lib/Makefile6
-rw-r--r--tests/run-make/staticlib-blank-lib/rmake.rs13
-rw-r--r--tests/run-make/test-benches/Makefile12
-rw-r--r--tests/run-make/test-benches/rmake.rs22
-rw-r--r--tests/run-make/version-verbose-commit-hash/rmake.rs20
-rw-r--r--tests/run-make/wasm-panic-small/rmake.rs9
-rw-r--r--tests/run-make/wasm-stringify-ints-small/rmake.rs8
-rw-r--r--tests/run-make/zero-extend-abi-param-passing/bad.c (renamed from tests/run-make/issue-97463-abi-param-passing/bad.c)0
-rw-r--r--tests/run-make/zero-extend-abi-param-passing/param_passing.rs (renamed from tests/run-make/issue-97463-abi-param-passing/param_passing.rs)0
-rw-r--r--tests/run-make/zero-extend-abi-param-passing/rmake.rs25
-rw-r--r--tests/rustdoc-gui/item-name-wrap.goml23
-rw-r--r--tests/rustdoc-gui/source-code-page-code-scroll.goml4
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs22
-rw-r--r--tests/rustdoc-gui/stab-in-doc.goml9
-rw-r--r--tests/rustdoc-gui/trait-with-bounds.goml35
-rw-r--r--tests/rustdoc-gui/type-declation-overflow.goml22
-rw-r--r--tests/rustdoc-ui/track-diagnostics.stderr2
-rw-r--r--tests/rustdoc/anchor-id-duplicate-method-name-25001.rs4
-rw-r--r--tests/rustdoc/const-generics/const-impl.rs2
-rw-r--r--tests/ui/check-cfg/mix.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/closures/binder/const-bound.rs3
-rw-r--r--tests/ui/closures/binder/const-bound.stderr8
-rw-r--r--tests/ui/coherence/negative-coherence/regions-in-canonical.rs5
-rw-r--r--tests/ui/coherence/negative-coherence/regions-in-canonical.stderr8
-rw-r--r--tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs3
-rw-r--r--tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr12
-rw-r--r--tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs1
-rw-r--r--tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr11
-rw-r--r--tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs7
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs14
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr42
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs4
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr8
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs8
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr24
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_good.rs13
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs10
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr20
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs10
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr32
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs9
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr16
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs12
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr33
-rw-r--r--tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs24
-rw-r--r--tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr17
-rw-r--r--tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs9
-rw-r--r--tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr84
-rw-r--r--tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs2
-rw-r--r--tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs11
-rw-r--r--tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr9
-rw-r--r--tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs27
-rw-r--r--tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr9
-rw-r--r--tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs5
-rw-r--r--tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr36
-rw-r--r--tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs13
-rw-r--r--tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr8
-rw-r--r--tests/ui/const-generics/adt_const_params/unsized_field-1.rs20
-rw-r--r--tests/ui/const-generics/adt_const_params/unsized_field-1.stderr36
-rw-r--r--tests/ui/const-generics/adt_const_params/unsized_field-2.rs14
-rw-r--r--tests/ui/const-generics/adt_const_params/unsized_field-2.stderr28
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.min.stderr20
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.rs6
-rw-r--r--tests/ui/const-generics/const-param-with-additional-obligations.rs6
-rw-r--r--tests/ui/const-generics/float-generic.adt_const_params.stderr2
-rw-r--r--tests/ui/const-generics/float-generic.full.stderr9
-rw-r--r--tests/ui/const-generics/float-generic.rs4
-rw-r--r--tests/ui/const-generics/float-generic.simple.stderr2
-rw-r--r--tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr15
-rw-r--r--tests/ui/const-generics/fn-const-param-call.full.stderr4
-rw-r--r--tests/ui/const-generics/fn-const-param-call.min.stderr4
-rw-r--r--tests/ui/const-generics/fn-const-param-call.rs8
-rw-r--r--tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr30
-rw-r--r--tests/ui/const-generics/fn-const-param-infer.full.stderr10
-rw-r--r--tests/ui/const-generics/fn-const-param-infer.min.stderr10
-rw-r--r--tests/ui/const-generics/fn-const-param-infer.rs32
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-100360.rs2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-89851.rs2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs8
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr14
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr14
-rw-r--r--tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs3
-rw-r--r--tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr8
-rw-r--r--tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr12
-rw-r--r--tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs7
-rw-r--r--tests/ui/const-generics/issue-66451.rs22
-rw-r--r--tests/ui/const-generics/issue-66451.stderr16
-rw-r--r--tests/ui/const-generics/issue-70408.rs2
-rw-r--r--tests/ui/const-generics/issue-80471.rs1
-rw-r--r--tests/ui/const-generics/issue-80471.stderr13
-rw-r--r--tests/ui/const-generics/issues/issue-100313.rs6
-rw-r--r--tests/ui/const-generics/issues/issue-105821.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.min.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs3
-rw-r--r--tests/ui/const-generics/issues/issue-71547.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs4
-rw-r--r--tests/ui/const-generics/issues/issue-86535-2.rs11
-rw-r--r--tests/ui/const-generics/issues/issue-86535.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-90455.fixed2
-rw-r--r--tests/ui/const-generics/issues/issue-90455.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-99641.stderr4
-rw-r--r--tests/ui/const-generics/min_const_generics/complex-types.stderr4
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr15
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr4
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr4
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param-deref.rs15
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr21
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param.full.stderr4
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param.min.stderr4
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param.rs6
-rw-r--r--tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr49
-rw-r--r--tests/ui/const-generics/slice-const-param-mismatch.full.stderr6
-rw-r--r--tests/ui/const-generics/slice-const-param-mismatch.min.stderr18
-rw-r--r--tests/ui/const-generics/slice-const-param-mismatch.rs11
-rw-r--r--tests/ui/const-generics/slice-const-param.rs7
-rw-r--r--tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr9
-rw-r--r--tests/ui/const-generics/transmute-const-param-static-reference.min.stderr6
-rw-r--r--tests/ui/const-generics/transmute-const-param-static-reference.rs13
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.min.stderr8
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.rs2
-rw-r--r--tests/ui/consts/refs_check_const_eq-issue-88384.rs17
-rw-r--r--tests/ui/consts/refs_check_const_eq-issue-88384.stderr12
-rw-r--r--tests/ui/consts/refs_check_const_value_eq-issue-88876.rs2
-rw-r--r--tests/ui/error-codes/E0771.rs4
-rw-r--r--tests/ui/error-codes/E0771.stderr8
-rw-r--r--tests/ui/errors/wrong-target-spec.rs8
-rw-r--r--tests/ui/errors/wrong-target-spec.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-adt_const_params.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-unsized-const-params.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-unsized-const-params.stderr18
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path.base.stderr6
-rw-r--r--tests/ui/generic-associated-types/issue-79422.base.stderr4
-rw-r--r--tests/ui/generic-const-items/elided-lifetimes.stderr4
-rw-r--r--tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs2
-rw-r--r--tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs2
-rw-r--r--tests/ui/inference/ice-cannot-relate-region-109178.rs2
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr4
-rw-r--r--tests/ui/lto/debuginfo-lto-alloc.rs3
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/repetitions.rs18
-rw-r--r--tests/ui/mir/ice-mir-const-qualif-125837.rs17
-rw-r--r--tests/ui/mir/ice-mir-const-qualif-125837.stderr41
-rw-r--r--tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr9
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr1
-rw-r--r--tests/ui/rust-2024/unsafe-env-suggestion.fixed2
-rw-r--r--tests/ui/rust-2024/unsafe-env-suggestion.rs2
-rw-r--r--tests/ui/rust-2024/unsafe-env-suggestion.stderr4
-rw-r--r--tests/ui/simd/intrinsic/generic-elements.rs20
-rw-r--r--tests/ui/simd/intrinsic/generic-elements.stderr42
-rw-r--r--tests/ui/simd/monomorphize-shuffle-index.rs2
-rw-r--r--tests/ui/statics/const_generics.rs2
-rw-r--r--tests/ui/symbol-names/const-generics-str-demangling.rs2
-rw-r--r--tests/ui/symbol-names/const-generics-structural-demangling.rs26
-rw-r--r--tests/ui/target-feature/gate.rs1
-rw-r--r--tests/ui/target-feature/gate.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs3
-rw-r--r--tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr8
-rw-r--r--tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs5
-rw-r--r--tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr12
-rw-r--r--tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs5
-rw-r--r--tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr8
-rw-r--r--tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs11
-rw-r--r--tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr17
-rw-r--r--tests/ui/try-trait/bad-interconversion.stderr16
-rw-r--r--tests/ui/try-trait/option-to-result.stderr8
-rw-r--r--tests/ui/try-trait/try-on-option.stderr4
-rw-r--r--tests/ui/typeck/ice-unexpected-region-123863.stderr8
-rw-r--r--tests/ui/wf/wf-unsafe-trait-obj-match.stderr4
-rw-r--r--triagebot.toml2
454 files changed, 10310 insertions, 5730 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 03584aed08d..b137497594f 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -64,11 +64,17 @@ jobs:
       - name: cargo update
         # Remove first line that always just says "Updating crates.io index"
         run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+      - name: cargo update rustbook
+        run: |
+          echo -e "\nrustbook dependencies:" >> cargo_update.log
+          cargo update --manifest-path src/tools/rustbook 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
       - name: upload Cargo.lock artifact for use in PR
         uses: actions/upload-artifact@v4
         with:
           name: Cargo-lock
-          path: Cargo.lock
+          path: |
+            Cargo.lock
+            src/tools/rustbook/Cargo.lock
           retention-days: 1
       - name: upload cargo-update log artifact for use in PR
         uses: actions/upload-artifact@v4
@@ -113,7 +119,7 @@ jobs:
           git config user.name github-actions
           git config user.email github-actions@github.com
           git switch --force-create cargo_update
-          git add ./Cargo.lock
+          git add ./Cargo.lock ./src/tools/rustbook/Cargo.lock
           git commit --no-verify --file=commit.txt
 
       - name: push
diff --git a/.gitignore b/.gitignore
index f1ca6a79b5c..87d02563ed0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,7 +50,6 @@ build/
 /target
 /src/bootstrap/target
 /src/tools/x/target
-/inc-fat/
 # Created by default with `src/ci/docker/run.sh`
 /obj/
 /rustc-ice*
diff --git a/.reuse/dep5 b/.reuse/dep5
deleted file mode 100644
index 5706ea0b204..00000000000
--- a/.reuse/dep5
+++ /dev/null
@@ -1,124 +0,0 @@
-# WARNING: this metadata is currently incomplete, do not rely on it yet.
-
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-
-# Note that we're explicitly listing the individual files at the root of the
-# repository rather than just having `Files: *`. This is explicitly done to
-# help downstream forks of the Rust compiler: this way, the files they add
-# won't be automatically marked as authored by the Rust project.
-Files: compiler/*
-       library/*
-       tests/*
-       src/*
-       .github/*
-       Cargo.lock
-       Cargo.toml
-       CODE_OF_CONDUCT.md
-       config.example.toml
-       configure
-       CONTRIBUTING.md
-       COPYRIGHT
-       INSTALL.md
-       LICENSE-APACHE
-       LICENSE-MIT
-       README.md
-       RELEASES.md
-       rustfmt.toml
-       rust-bors.toml
-       triagebot.toml
-       x
-       x.ps1
-       x.py
-       .clang-format
-       .editorconfig
-       .git-blame-ignore-revs
-       .gitattributes
-       .gitignore
-       .gitmodules
-       .mailmap
-       .ignore
-Copyright: The Rust Project Developers (see https://thanks.rust-lang.org)
-License: MIT or Apache-2.0
-
-Files: compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
-Copyright: 2003-2019 University of Illinois at Urbana-Champaign.
-           The Rust Project Developers (see https://thanks.rust-lang.org)
-License: Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT)
-
-Files: library/core/src/unicode/unicode_data.rs
-Copyright: 1991-2022 Unicode, Inc. All rights reserved.
-License: Unicode-DFS-2016
-
-Files: library/std/src/sync/mpmc/*
-Copyright: 2019 The Crossbeam Project Developers
-           The Rust Project Developers (see https://thanks.rust-lang.org)
-License: MIT OR Apache-2.0
-
-Files: library/std/src/sys/sync/mutex/fuchsia.rs
-Copyright: 2016 The Fuchsia Authors
-           The Rust Project Developers (see https://thanks.rust-lang.org)
-License: BSD-2-Clause AND (MIT OR Apache-2.0)
-
-Files: src/test/rustdoc/auxiliary/enum-primitive.rs
-Copyright: 2015 Anders Kaseorg <andersk@mit.edu>
-License: MIT
-
-Files: src/librustdoc/html/static/fonts/FiraSans*
-Copyright: 2014, Mozilla Foundation
-           2014, Telefonica S.A.
-License: OFL-1.1
-
-Files: src/librustdoc/html/static/fonts/NanumBarun*
-Copyright: 2010 NAVER Corporation
-License: OFL-1.1
-
-Files: src/librustdoc/html/static/fonts/SourceCodePro*
-       src/librustdoc/html/static/fonts/SourceSerif4*
-Copyright: 2010, 2012, 2014-2023, Adobe Systems Incorporated
-License: OFL-1.1
-
-Files: src/librustdoc/html/static/css/normalize.css
-Copyright: Nicolas Gallagher and Jonathan Neal
-License: MIT
-
-Files: src/librustdoc/html/static/css/rustdoc.css
-Copyright: 2016 Ike Ku, Jessica Stokes and Leon Guan
-           The Rust Project Developers (see https://thanks.rust-lang.org)
-License: MIT OR Apache-2.0
-
-Files: src/doc/rustc-dev-guide/mermaid.min.js
-Copyright: 2014-2021 Knut Sveidqvist
-License: MIT
-
-Files: library/backtrace/*
-Copyright: 2014 Alex Crichton
-           The Rust Project Developers (see https://thanks.rust-lang.org)
-License: MIT OR Apache-2.0
-
-Files: src/doc/embedded-book/*
-Copyright: Rust on Embedded Devices Working Group
-           The Rust Project Developers (see https://thanks.rust-lang.org)
-License: MIT OR Apache-2.0 OR CC-BY-SA-4.0
-
-Files: src/doc/rust-by-example/*
-Copyright: 2014 Jorge Aparicio
-           The Rust Project Developers (see https://thanks.rust-lang.org)
-License: MIT OR Apache-2.0
-
-# Reuse cannot process the LLVM source tree, and so the copyrights for the LLVM
-# submodule are written out here manually. The collect-licence-metadata tool
-# has a specific exception coded within it to ignore ./src/llvm-project so
-# any time LLVM is updated, please revisit this section. The copyrights are
-# taken from the relevant LLVM sub-folders: llvm, lld, lldb, compiler-rt and libunwind.
-#
-# The git hash for the CREDITS.TXT file is taken from the current git submodule
-# commit for ./src/llvm-project.
-#
-# The copyright years were compiled by looking at all the relevant
-# ./src/llvm-project/*/LICENSE.txt files
-
-Files: src/llvm-project/*
-Copyright: 2003-2019 by the contributors listed in [CREDITS.TXT](https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT)
-           2010 Apple Inc
-           2003-2019 University of Illinois at Urbana-Champaign.
-License: NCSA AND Apache-2.0 WITH LLVM-exception
diff --git a/Cargo.lock b/Cargo.lock
index 1c1607e4c1a..64a7cec030a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -285,21 +285,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "assert_cmd"
-version = "2.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8"
-dependencies = [
- "anstyle",
- "bstr",
- "doc-comment",
- "predicates",
- "predicates-core",
- "predicates-tree",
- "wait-timeout",
-]
-
-[[package]]
 name = "autocfg"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1112,12 +1097,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
 
 [[package]]
-name = "difflib"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
-
-[[package]]
 name = "digest"
 version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1209,12 +1188,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "doc-comment"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
-
-[[package]]
 name = "either"
 version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2204,21 +2177,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "line-wrap"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e"
-
-[[package]]
-name = "linereader"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d921fea6860357575519aca014c6e22470585accdd543b370c404a8a72d0dd1d"
-dependencies = [
- "memchr",
-]
-
-[[package]]
 name = "linkchecker"
 version = "0.1.0"
 dependencies = [
@@ -2227,12 +2185,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "linked-hash-map"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
-
-[[package]]
 name = "lint-docs"
 version = "0.1.0"
 dependencies = [
@@ -2369,52 +2321,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "mdbook-i18n-helpers"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c8f972ab672d366c3dad77ea5aa7bae68db2d25fbeb889849f97469d7b658e4"
-dependencies = [
- "anyhow",
- "chrono",
- "mdbook",
- "polib",
- "pulldown-cmark 0.10.3",
- "pulldown-cmark-to-cmark",
- "regex",
- "semver",
- "serde_json",
- "syntect",
- "textwrap",
-]
-
-[[package]]
-name = "mdbook-trpl-listing"
-version = "0.1.0"
-dependencies = [
- "assert_cmd",
- "clap",
- "mdbook",
- "pulldown-cmark 0.10.3",
- "pulldown-cmark-to-cmark",
- "serde_json",
- "thiserror",
- "toml 0.8.14",
- "xmlparser",
-]
-
-[[package]]
-name = "mdbook-trpl-note"
-version = "1.0.0"
-dependencies = [
- "assert_cmd",
- "clap",
- "mdbook",
- "pulldown-cmark 0.10.3",
- "pulldown-cmark-to-cmark",
- "serde_json",
-]
-
-[[package]]
 name = "measureme"
 version = "11.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2599,12 +2505,76 @@ dependencies = [
 ]
 
 [[package]]
+name = "num"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
+dependencies = [
+ "num-bigint",
+ "num-complex",
+ "num-integer",
+ "num-iter",
+ "num-rational",
+ "num-traits",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
 name = "num-conv"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
 
 [[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
+dependencies = [
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
 name = "num-traits"
 version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2692,28 +2662,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
-name = "onig"
-version = "6.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
-dependencies = [
- "bitflags 1.3.2",
- "libc",
- "once_cell",
- "onig_sys",
-]
-
-[[package]]
-name = "onig_sys"
-version = "69.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
-dependencies = [
- "cc",
- "pkg-config",
-]
-
-[[package]]
 name = "opener"
 version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3013,29 +2961,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
 
 [[package]]
-name = "plist"
-version = "1.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9"
-dependencies = [
- "base64",
- "indexmap",
- "line-wrap",
- "quick-xml",
- "serde",
- "time",
-]
-
-[[package]]
-name = "polib"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b393b155cf9be86249cba1b56cc81be0e6212c66d94ac0d76d37a1761f3bb1b"
-dependencies = [
- "linereader",
-]
-
-[[package]]
 name = "polonius-engine"
 version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3071,33 +2996,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
-name = "predicates"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
-dependencies = [
- "anstyle",
- "difflib",
- "predicates-core",
-]
-
-[[package]]
-name = "predicates-core"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
-
-[[package]]
-name = "predicates-tree"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
-dependencies = [
- "predicates-core",
- "termtree",
-]
-
-[[package]]
 name = "prettydiff"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3166,7 +3064,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
 dependencies = [
  "bitflags 2.5.0",
- "getopts",
  "memchr",
  "pulldown-cmark-escape 0.10.1",
  "unicase",
@@ -3197,30 +3094,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
 
 [[package]]
-name = "pulldown-cmark-to-cmark"
-version = "13.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f609795c8d835f79dcfcf768415b9fb57ef1b74891e99f86e73f43a7a257163b"
-dependencies = [
- "pulldown-cmark 0.10.3",
-]
-
-[[package]]
 name = "punycode"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe"
 
 [[package]]
-name = "quick-xml"
-version = "0.31.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
-dependencies = [
- "memchr",
-]
-
-[[package]]
 name = "quine-mc_cluskey"
 version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3455,18 +3334,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustbook"
-version = "0.1.0"
-dependencies = [
- "clap",
- "env_logger",
- "mdbook",
- "mdbook-i18n-helpers",
- "mdbook-trpl-listing",
- "mdbook-trpl-note",
-]
-
-[[package]]
 name = "rustc-build-sysroot"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5486,28 +5353,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "syntect"
-version = "5.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
-dependencies = [
- "bincode",
- "bitflags 1.3.2",
- "flate2",
- "fnv",
- "once_cell",
- "onig",
- "plist",
- "regex-syntax 0.8.4",
- "serde",
- "serde_derive",
- "serde_json",
- "thiserror",
- "walkdir",
- "yaml-rust",
-]
-
-[[package]]
 name = "sysinfo"
 version = "0.30.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5615,12 +5460,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "termtree"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
-
-[[package]]
 name = "test"
 version = "0.0.0"
 dependencies = [
@@ -5631,10 +5470,15 @@ dependencies = [
 ]
 
 [[package]]
-name = "textwrap"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
+name = "test-float-parse"
+version = "0.1.0"
+dependencies = [
+ "indicatif",
+ "num",
+ "rand",
+ "rand_chacha",
+ "rayon",
+]
 
 [[package]]
 name = "thin-vec"
@@ -5799,19 +5643,7 @@ dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
- "toml_edit 0.19.15",
-]
-
-[[package]]
-name = "toml"
-version = "0.8.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit 0.22.14",
+ "toml_edit",
 ]
 
 [[package]]
@@ -5833,20 +5665,7 @@ dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
- "winnow 0.5.40",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "winnow 0.6.13",
+ "winnow",
 ]
 
 [[package]]
@@ -6257,15 +6076,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
-name = "wait-timeout"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
-dependencies = [
- "libc",
-]
-
-[[package]]
 name = "walkdir"
 version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6670,15 +6480,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "winnow"
-version = "0.6.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
-dependencies = [
- "memchr",
-]
-
-[[package]]
 name = "wit-component"
 version = "0.210.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6733,12 +6534,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "xmlparser"
-version = "0.13.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
-
-[[package]]
 name = "xz2"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6748,15 +6543,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "yaml-rust"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
-dependencies = [
- "linked-hash-map",
-]
-
-[[package]]
 name = "yansi-term"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index ce87a8c20b7..178a5ab9408 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,6 +4,7 @@ members = [
   "compiler/rustc",
   "library/std",
   "library/sysroot",
+  "src/etc/test-float-parse",
   "src/rustdoc-json-types",
   "src/tools/build_helper",
   "src/tools/cargotest",
@@ -15,7 +16,6 @@ members = [
   "src/tools/linkchecker",
   "src/tools/lint-docs",
   "src/tools/miropt-test-tools",
-  "src/tools/rustbook",
   "src/tools/unstable-book-gen",
   "src/tools/tidy",
   "src/tools/tier-check",
@@ -109,6 +109,18 @@ strip = true
 debug = 0
 strip = true
 
+# Bigint libraries are slow without optimization, speed up testing
+[profile.dev.package.test-float-parse]
+opt-level = 3
+
+# Speed up the binary as much as possible
+[profile.release.package.test-float-parse]
+opt-level = 3
+codegen-units = 1
+# FIXME: LTO cannot be enabled for binaries in a workspace
+# <https://github.com/rust-lang/cargo/issues/9330>
+# lto = true
+
 [patch.crates-io]
 # See comments in `library/rustc-std-workspace-core/README.md` for what's going on
 # here
diff --git a/LICENSES/CC-BY-3.0.txt b/LICENSES/CC-BY-3.0.txt
deleted file mode 100644
index bd32fa8477b..00000000000
--- a/LICENSES/CC-BY-3.0.txt
+++ /dev/null
@@ -1,319 +0,0 @@
-Creative Commons Legal Code
-
-Attribution 3.0 Unported
-
-    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
-    LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
-    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
-    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
-    REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
-    DAMAGES RESULTING FROM ITS USE.
-
-License
-
-THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
-COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
-COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
-AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
-
-BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
-TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
-BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
-CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
-CONDITIONS.
-
-1. Definitions
-
- a. "Adaptation" means a work based upon the Work, or upon the Work and
-    other pre-existing works, such as a translation, adaptation,
-    derivative work, arrangement of music or other alterations of a
-    literary or artistic work, or phonogram or performance and includes
-    cinematographic adaptations or any other form in which the Work may be
-    recast, transformed, or adapted including in any form recognizably
-    derived from the original, except that a work that constitutes a
-    Collection will not be considered an Adaptation for the purpose of
-    this License. For the avoidance of doubt, where the Work is a musical
-    work, performance or phonogram, the synchronization of the Work in
-    timed-relation with a moving image ("synching") will be considered an
-    Adaptation for the purpose of this License.
- b. "Collection" means a collection of literary or artistic works, such as
-    encyclopedias and anthologies, or performances, phonograms or
-    broadcasts, or other works or subject matter other than works listed
-    in Section 1(f) below, which, by reason of the selection and
-    arrangement of their contents, constitute intellectual creations, in
-    which the Work is included in its entirety in unmodified form along
-    with one or more other contributions, each constituting separate and
-    independent works in themselves, which together are assembled into a
-    collective whole. A work that constitutes a Collection will not be
-    considered an Adaptation (as defined above) for the purposes of this
-    License.
- c. "Distribute" means to make available to the public the original and
-    copies of the Work or Adaptation, as appropriate, through sale or
-    other transfer of ownership.
- d. "Licensor" means the individual, individuals, entity or entities that
-    offer(s) the Work under the terms of this License.
- e. "Original Author" means, in the case of a literary or artistic work,
-    the individual, individuals, entity or entities who created the Work
-    or if no individual or entity can be identified, the publisher; and in
-    addition (i) in the case of a performance the actors, singers,
-    musicians, dancers, and other persons who act, sing, deliver, declaim,
-    play in, interpret or otherwise perform literary or artistic works or
-    expressions of folklore; (ii) in the case of a phonogram the producer
-    being the person or legal entity who first fixes the sounds of a
-    performance or other sounds; and, (iii) in the case of broadcasts, the
-    organization that transmits the broadcast.
- f. "Work" means the literary and/or artistic work offered under the terms
-    of this License including without limitation any production in the
-    literary, scientific and artistic domain, whatever may be the mode or
-    form of its expression including digital form, such as a book,
-    pamphlet and other writing; a lecture, address, sermon or other work
-    of the same nature; a dramatic or dramatico-musical work; a
-    choreographic work or entertainment in dumb show; a musical
-    composition with or without words; a cinematographic work to which are
-    assimilated works expressed by a process analogous to cinematography;
-    a work of drawing, painting, architecture, sculpture, engraving or
-    lithography; a photographic work to which are assimilated works
-    expressed by a process analogous to photography; a work of applied
-    art; an illustration, map, plan, sketch or three-dimensional work
-    relative to geography, topography, architecture or science; a
-    performance; a broadcast; a phonogram; a compilation of data to the
-    extent it is protected as a copyrightable work; or a work performed by
-    a variety or circus performer to the extent it is not otherwise
-    considered a literary or artistic work.
- g. "You" means an individual or entity exercising rights under this
-    License who has not previously violated the terms of this License with
-    respect to the Work, or who has received express permission from the
-    Licensor to exercise rights under this License despite a previous
-    violation.
- h. "Publicly Perform" means to perform public recitations of the Work and
-    to communicate to the public those public recitations, by any means or
-    process, including by wire or wireless means or public digital
-    performances; to make available to the public Works in such a way that
-    members of the public may access these Works from a place and at a
-    place individually chosen by them; to perform the Work to the public
-    by any means or process and the communication to the public of the
-    performances of the Work, including by public digital performance; to
-    broadcast and rebroadcast the Work by any means including signs,
-    sounds or images.
- i. "Reproduce" means to make copies of the Work by any means including
-    without limitation by sound or visual recordings and the right of
-    fixation and reproducing fixations of the Work, including storage of a
-    protected performance or phonogram in digital form or other electronic
-    medium.
-
-2. Fair Dealing Rights. Nothing in this License is intended to reduce,
-limit, or restrict any uses free from copyright or rights arising from
-limitations or exceptions that are provided for in connection with the
-copyright protection under copyright law or other applicable laws.
-
-3. License Grant. Subject to the terms and conditions of this License,
-Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
-perpetual (for the duration of the applicable copyright) license to
-exercise the rights in the Work as stated below:
-
- a. to Reproduce the Work, to incorporate the Work into one or more
-    Collections, and to Reproduce the Work as incorporated in the
-    Collections;
- b. to create and Reproduce Adaptations provided that any such Adaptation,
-    including any translation in any medium, takes reasonable steps to
-    clearly label, demarcate or otherwise identify that changes were made
-    to the original Work. For example, a translation could be marked "The
-    original work was translated from English to Spanish," or a
-    modification could indicate "The original work has been modified.";
- c. to Distribute and Publicly Perform the Work including as incorporated
-    in Collections; and,
- d. to Distribute and Publicly Perform Adaptations.
- e. For the avoidance of doubt:
-
-     i. Non-waivable Compulsory License Schemes. In those jurisdictions in
-        which the right to collect royalties through any statutory or
-        compulsory licensing scheme cannot be waived, the Licensor
-        reserves the exclusive right to collect such royalties for any
-        exercise by You of the rights granted under this License;
-    ii. Waivable Compulsory License Schemes. In those jurisdictions in
-        which the right to collect royalties through any statutory or
-        compulsory licensing scheme can be waived, the Licensor waives the
-        exclusive right to collect such royalties for any exercise by You
-        of the rights granted under this License; and,
-   iii. Voluntary License Schemes. The Licensor waives the right to
-        collect royalties, whether individually or, in the event that the
-        Licensor is a member of a collecting society that administers
-        voluntary licensing schemes, via that society, from any exercise
-        by You of the rights granted under this License.
-
-The above rights may be exercised in all media and formats whether now
-known or hereafter devised. The above rights include the right to make
-such modifications as are technically necessary to exercise the rights in
-other media and formats. Subject to Section 8(f), all rights not expressly
-granted by Licensor are hereby reserved.
-
-4. Restrictions. The license granted in Section 3 above is expressly made
-subject to and limited by the following restrictions:
-
- a. You may Distribute or Publicly Perform the Work only under the terms
-    of this License. You must include a copy of, or the Uniform Resource
-    Identifier (URI) for, this License with every copy of the Work You
-    Distribute or Publicly Perform. You may not offer or impose any terms
-    on the Work that restrict the terms of this License or the ability of
-    the recipient of the Work to exercise the rights granted to that
-    recipient under the terms of the License. You may not sublicense the
-    Work. You must keep intact all notices that refer to this License and
-    to the disclaimer of warranties with every copy of the Work You
-    Distribute or Publicly Perform. When You Distribute or Publicly
-    Perform the Work, You may not impose any effective technological
-    measures on the Work that restrict the ability of a recipient of the
-    Work from You to exercise the rights granted to that recipient under
-    the terms of the License. This Section 4(a) applies to the Work as
-    incorporated in a Collection, but this does not require the Collection
-    apart from the Work itself to be made subject to the terms of this
-    License. If You create a Collection, upon notice from any Licensor You
-    must, to the extent practicable, remove from the Collection any credit
-    as required by Section 4(b), as requested. If You create an
-    Adaptation, upon notice from any Licensor You must, to the extent
-    practicable, remove from the Adaptation any credit as required by
-    Section 4(b), as requested.
- b. If You Distribute, or Publicly Perform the Work or any Adaptations or
-    Collections, You must, unless a request has been made pursuant to
-    Section 4(a), keep intact all copyright notices for the Work and
-    provide, reasonable to the medium or means You are utilizing: (i) the
-    name of the Original Author (or pseudonym, if applicable) if supplied,
-    and/or if the Original Author and/or Licensor designate another party
-    or parties (e.g., a sponsor institute, publishing entity, journal) for
-    attribution ("Attribution Parties") in Licensor's copyright notice,
-    terms of service or by other reasonable means, the name of such party
-    or parties; (ii) the title of the Work if supplied; (iii) to the
-    extent reasonably practicable, the URI, if any, that Licensor
-    specifies to be associated with the Work, unless such URI does not
-    refer to the copyright notice or licensing information for the Work;
-    and (iv) , consistent with Section 3(b), in the case of an Adaptation,
-    a credit identifying the use of the Work in the Adaptation (e.g.,
-    "French translation of the Work by Original Author," or "Screenplay
-    based on original Work by Original Author"). The credit required by
-    this Section 4 (b) may be implemented in any reasonable manner;
-    provided, however, that in the case of a Adaptation or Collection, at
-    a minimum such credit will appear, if a credit for all contributing
-    authors of the Adaptation or Collection appears, then as part of these
-    credits and in a manner at least as prominent as the credits for the
-    other contributing authors. For the avoidance of doubt, You may only
-    use the credit required by this Section for the purpose of attribution
-    in the manner set out above and, by exercising Your rights under this
-    License, You may not implicitly or explicitly assert or imply any
-    connection with, sponsorship or endorsement by the Original Author,
-    Licensor and/or Attribution Parties, as appropriate, of You or Your
-    use of the Work, without the separate, express prior written
-    permission of the Original Author, Licensor and/or Attribution
-    Parties.
- c. Except as otherwise agreed in writing by the Licensor or as may be
-    otherwise permitted by applicable law, if You Reproduce, Distribute or
-    Publicly Perform the Work either by itself or as part of any
-    Adaptations or Collections, You must not distort, mutilate, modify or
-    take other derogatory action in relation to the Work which would be
-    prejudicial to the Original Author's honor or reputation. Licensor
-    agrees that in those jurisdictions (e.g. Japan), in which any exercise
-    of the right granted in Section 3(b) of this License (the right to
-    make Adaptations) would be deemed to be a distortion, mutilation,
-    modification or other derogatory action prejudicial to the Original
-    Author's honor and reputation, the Licensor will waive or not assert,
-    as appropriate, this Section, to the fullest extent permitted by the
-    applicable national law, to enable You to reasonably exercise Your
-    right under Section 3(b) of this License (right to make Adaptations)
-    but not otherwise.
-
-5. Representations, Warranties and Disclaimer
-
-UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
-OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
-KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
-INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
-FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
-LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
-WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
-OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
-
-6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
-LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
-ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
-ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
-BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. Termination
-
- a. This License and the rights granted hereunder will terminate
-    automatically upon any breach by You of the terms of this License.
-    Individuals or entities who have received Adaptations or Collections
-    from You under this License, however, will not have their licenses
-    terminated provided such individuals or entities remain in full
-    compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
-    survive any termination of this License.
- b. Subject to the above terms and conditions, the license granted here is
-    perpetual (for the duration of the applicable copyright in the Work).
-    Notwithstanding the above, Licensor reserves the right to release the
-    Work under different license terms or to stop distributing the Work at
-    any time; provided, however that any such election will not serve to
-    withdraw this License (or any other license that has been, or is
-    required to be, granted under the terms of this License), and this
-    License will continue in full force and effect unless terminated as
-    stated above.
-
-8. Miscellaneous
-
- a. Each time You Distribute or Publicly Perform the Work or a Collection,
-    the Licensor offers to the recipient a license to the Work on the same
-    terms and conditions as the license granted to You under this License.
- b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
-    offers to the recipient a license to the original Work on the same
-    terms and conditions as the license granted to You under this License.
- c. If any provision of this License is invalid or unenforceable under
-    applicable law, it shall not affect the validity or enforceability of
-    the remainder of the terms of this License, and without further action
-    by the parties to this agreement, such provision shall be reformed to
-    the minimum extent necessary to make such provision valid and
-    enforceable.
- d. No term or provision of this License shall be deemed waived and no
-    breach consented to unless such waiver or consent shall be in writing
-    and signed by the party to be charged with such waiver or consent.
- e. This License constitutes the entire agreement between the parties with
-    respect to the Work licensed here. There are no understandings,
-    agreements or representations with respect to the Work not specified
-    here. Licensor shall not be bound by any additional provisions that
-    may appear in any communication from You. This License may not be
-    modified without the mutual written agreement of the Licensor and You.
- f. The rights granted under, and the subject matter referenced, in this
-    License were drafted utilizing the terminology of the Berne Convention
-    for the Protection of Literary and Artistic Works (as amended on
-    September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
-    Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
-    and the Universal Copyright Convention (as revised on July 24, 1971).
-    These rights and subject matter take effect in the relevant
-    jurisdiction in which the License terms are sought to be enforced
-    according to the corresponding provisions of the implementation of
-    those treaty provisions in the applicable national law. If the
-    standard suite of rights granted under applicable copyright law
-    includes additional rights not granted under this License, such
-    additional rights are deemed to be included in the License; this
-    License is not intended to restrict the license of any rights under
-    applicable law.
-
-
-Creative Commons Notice
-
-    Creative Commons is not a party to this License, and makes no warranty
-    whatsoever in connection with the Work. Creative Commons will not be
-    liable to You or any party on any legal theory for any damages
-    whatsoever, including without limitation any general, special,
-    incidental or consequential damages arising in connection to this
-    license. Notwithstanding the foregoing two (2) sentences, if Creative
-    Commons has expressly identified itself as the Licensor hereunder, it
-    shall have all rights and obligations of Licensor.
-
-    Except for the limited purpose of indicating to the public that the
-    Work is licensed under the CCPL, Creative Commons does not authorize
-    the use by either party of the trademark "Creative Commons" or any
-    related trademark or logo of Creative Commons without the prior
-    written consent of Creative Commons. Any permitted use will be in
-    compliance with Creative Commons' then-current trademark usage
-    guidelines, as may be published on its website or otherwise made
-    available upon request from time to time. For the avoidance of doubt,
-    this trademark restriction does not form part of this License.
-
-    Creative Commons may be contacted at https://creativecommons.org/.
\ No newline at end of file
diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt
deleted file mode 100644
index 0e259d42c99..00000000000
--- a/LICENSES/CC0-1.0.txt
+++ /dev/null
@@ -1,121 +0,0 @@
-Creative Commons Legal Code
-
-CC0 1.0 Universal
-
-    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
-    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
-    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
-    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
-    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
-    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
-    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
-    HEREUNDER.
-
-Statement of Purpose
-
-The laws of most jurisdictions throughout the world automatically confer
-exclusive Copyright and Related Rights (defined below) upon the creator
-and subsequent owner(s) (each and all, an "owner") of an original work of
-authorship and/or a database (each, a "Work").
-
-Certain owners wish to permanently relinquish those rights to a Work for
-the purpose of contributing to a commons of creative, cultural and
-scientific works ("Commons") that the public can reliably and without fear
-of later claims of infringement build upon, modify, incorporate in other
-works, reuse and redistribute as freely as possible in any form whatsoever
-and for any purposes, including without limitation commercial purposes.
-These owners may contribute to the Commons to promote the ideal of a free
-culture and the further production of creative, cultural and scientific
-works, or to gain reputation or greater distribution for their Work in
-part through the use and efforts of others.
-
-For these and/or other purposes and motivations, and without any
-expectation of additional consideration or compensation, the person
-associating CC0 with a Work (the "Affirmer"), to the extent that he or she
-is an owner of Copyright and Related Rights in the Work, voluntarily
-elects to apply CC0 to the Work and publicly distribute the Work under its
-terms, with knowledge of his or her Copyright and Related Rights in the
-Work and the meaning and intended legal effect of CC0 on those rights.
-
-1. Copyright and Related Rights. A Work made available under CC0 may be
-protected by copyright and related or neighboring rights ("Copyright and
-Related Rights"). Copyright and Related Rights include, but are not
-limited to, the following:
-
-  i. the right to reproduce, adapt, distribute, perform, display,
-     communicate, and translate a Work;
- ii. moral rights retained by the original author(s) and/or performer(s);
-iii. publicity and privacy rights pertaining to a person's image or
-     likeness depicted in a Work;
- iv. rights protecting against unfair competition in regards to a Work,
-     subject to the limitations in paragraph 4(a), below;
-  v. rights protecting the extraction, dissemination, use and reuse of data
-     in a Work;
- vi. database rights (such as those arising under Directive 96/9/EC of the
-     European Parliament and of the Council of 11 March 1996 on the legal
-     protection of databases, and under any national implementation
-     thereof, including any amended or successor version of such
-     directive); and
-vii. other similar, equivalent or corresponding rights throughout the
-     world based on applicable law or treaty, and any national
-     implementations thereof.
-
-2. Waiver. To the greatest extent permitted by, but not in contravention
-of, applicable law, Affirmer hereby overtly, fully, permanently,
-irrevocably and unconditionally waives, abandons, and surrenders all of
-Affirmer's Copyright and Related Rights and associated claims and causes
-of action, whether now known or unknown (including existing as well as
-future claims and causes of action), in the Work (i) in all territories
-worldwide, (ii) for the maximum duration provided by applicable law or
-treaty (including future time extensions), (iii) in any current or future
-medium and for any number of copies, and (iv) for any purpose whatsoever,
-including without limitation commercial, advertising or promotional
-purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
-member of the public at large and to the detriment of Affirmer's heirs and
-successors, fully intending that such Waiver shall not be subject to
-revocation, rescission, cancellation, termination, or any other legal or
-equitable action to disrupt the quiet enjoyment of the Work by the public
-as contemplated by Affirmer's express Statement of Purpose.
-
-3. Public License Fallback. Should any part of the Waiver for any reason
-be judged legally invalid or ineffective under applicable law, then the
-Waiver shall be preserved to the maximum extent permitted taking into
-account Affirmer's express Statement of Purpose. In addition, to the
-extent the Waiver is so judged Affirmer hereby grants to each affected
-person a royalty-free, non transferable, non sublicensable, non exclusive,
-irrevocable and unconditional license to exercise Affirmer's Copyright and
-Related Rights in the Work (i) in all territories worldwide, (ii) for the
-maximum duration provided by applicable law or treaty (including future
-time extensions), (iii) in any current or future medium and for any number
-of copies, and (iv) for any purpose whatsoever, including without
-limitation commercial, advertising or promotional purposes (the
-"License"). The License shall be deemed effective as of the date CC0 was
-applied by Affirmer to the Work. Should any part of the License for any
-reason be judged legally invalid or ineffective under applicable law, such
-partial invalidity or ineffectiveness shall not invalidate the remainder
-of the License, and in such case Affirmer hereby affirms that he or she
-will not (i) exercise any of his or her remaining Copyright and Related
-Rights in the Work or (ii) assert any associated claims and causes of
-action with respect to the Work, in either case contrary to Affirmer's
-express Statement of Purpose.
-
-4. Limitations and Disclaimers.
-
- a. No trademark or patent rights held by Affirmer are waived, abandoned,
-    surrendered, licensed or otherwise affected by this document.
- b. Affirmer offers the Work as-is and makes no representations or
-    warranties of any kind concerning the Work, express, implied,
-    statutory or otherwise, including without limitation warranties of
-    title, merchantability, fitness for a particular purpose, non
-    infringement, or the absence of latent or other defects, accuracy, or
-    the present or absence of errors, whether or not discoverable, all to
-    the greatest extent permissible under applicable law.
- c. Affirmer disclaims responsibility for clearing rights of other persons
-    that may apply to the Work or any use thereof, including without
-    limitation any person's Copyright and Related Rights in the Work.
-    Further, Affirmer disclaims responsibility for obtaining any necessary
-    consents, permissions or other rights required for any use of the
-    Work.
- d. Affirmer understands and acknowledges that Creative Commons is not a
-    party to this document and has no duty or obligation with respect to
-    this CC0 or use of the Work.
diff --git a/REUSE.toml b/REUSE.toml
new file mode 100644
index 00000000000..1a30d8016c9
--- /dev/null
+++ b/REUSE.toml
@@ -0,0 +1,170 @@
+version = 1
+
+# Reuse annotations file.
+#
+# This file controls how reuse-tool finds copyright and license notices within
+# source files. As the tool has a habit of picking up random uses of the word
+# 'Copyright' within source code, and because it will complain that other files
+# do not contain any specific copyright and license notifications, we usually
+# just set a blanket license and copyright notice for a whole sub-tree at a
+# time.
+#
+# See https://reuse.software and https://github.com/fsfe/reuse-tool for more
+# details. We currently use reuse-tool version 4.0.3.
+
+[[annotations]]
+path = [
+    "compiler/**",
+    "library/**",
+    "tests/**",
+    "src/**",
+    ".github/**",
+    "Cargo.lock",
+    "Cargo.toml",
+    "CODE_OF_CONDUCT.md",
+    "config.example.toml",
+    "configure",
+    "CONTRIBUTING.md",
+    "COPYRIGHT",
+    "INSTALL.md",
+    "LICENSE-APACHE",
+    "LICENSE-MIT",
+    "README.md",
+    "RELEASES.md",
+    "REUSE.toml",
+    "rustfmt.toml",
+    "rust-bors.toml",
+    "triagebot.toml",
+    "x",
+    "x.ps1",
+    "x.py",
+    ".clang-format",
+    ".editorconfig",
+    ".git-blame-ignore-revs",
+    ".gitattributes",
+    ".gitignore",
+    ".gitmodules",
+    ".mailmap",
+    ".ignore",
+]
+precedence = "override"
+SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)"
+SPDX-License-Identifier = "MIT or Apache-2.0"
+
+[[annotations]]
+path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "2003-2019 University of Illinois at Urbana-Champaign.",
+    "The Rust Project Developers (see https://thanks.rust-lang.org)",
+]
+SPDX-License-Identifier = "Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT)"
+
+[[annotations]]
+path = "library/core/src/unicode/unicode_data.rs"
+precedence = "override"
+SPDX-FileCopyrightText = "1991-2022 Unicode, Inc. All rights reserved."
+SPDX-License-Identifier = "Unicode-DFS-2016"
+
+[[annotations]]
+path = "library/std/src/sync/mpmc/**"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "2019 The Crossbeam Project Developers",
+    "The Rust Project Developers (see https://thanks.rust-lang.org)",
+]
+SPDX-License-Identifier = "MIT OR Apache-2.0"
+
+[[annotations]]
+path = "library/std/src/sys/sync/mutex/fuchsia.rs"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "2016 The Fuchsia Authors",
+    "The Rust Project Developers (see https://thanks.rust-lang.org)",
+]
+SPDX-License-Identifier = "BSD-2-Clause AND (MIT OR Apache-2.0)"
+
+[[annotations]]
+path = "src/test/rustdoc/auxiliary/enum-primitive.rs"
+precedence = "override"
+SPDX-FileCopyrightText = "2015 Anders Kaseorg <andersk@mit.edu>"
+SPDX-License-Identifier = "MIT"
+
+[[annotations]]
+path = "src/librustdoc/html/static/fonts/FiraSans**"
+precedence = "override"
+SPDX-FileCopyrightText = ["2014, Mozilla Foundation", "2014, Telefonica S.A."]
+SPDX-License-Identifier = "OFL-1.1"
+
+[[annotations]]
+path = "src/librustdoc/html/static/fonts/NanumBarun**"
+precedence = "override"
+SPDX-FileCopyrightText = "2010 NAVER Corporation"
+SPDX-License-Identifier = "OFL-1.1"
+
+[[annotations]]
+path = [
+    "src/librustdoc/html/static/fonts/SourceCodePro**",
+    "src/librustdoc/html/static/fonts/SourceSerif4**",
+]
+precedence = "override"
+SPDX-FileCopyrightText = "2010, 2012, 2014-2023, Adobe Systems Incorporated"
+SPDX-License-Identifier = "OFL-1.1"
+
+[[annotations]]
+path = "src/librustdoc/html/static/css/normalize.css"
+precedence = "override"
+SPDX-FileCopyrightText = "Nicolas Gallagher and Jonathan Neal"
+SPDX-License-Identifier = "MIT"
+
+[[annotations]]
+path = "src/librustdoc/html/static/css/rustdoc.css"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "2016 Ike Ku, Jessica Stokes and Leon Guan",
+    "The Rust Project Developers (see https://thanks.rust-lang.org)",
+]
+SPDX-License-Identifier = "MIT OR Apache-2.0"
+
+[[annotations]]
+path = "src/doc/rustc-dev-guide/mermaid.min.js"
+precedence = "override"
+SPDX-FileCopyrightText = "2014-2021 Knut Sveidqvist"
+SPDX-License-Identifier = "MIT"
+
+[[annotations]]
+path = "library/backtrace/**"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "2014 Alex Crichton",
+    "The Rust Project Developers (see https://thanks.rust-lang.org)",
+]
+SPDX-License-Identifier = "MIT OR Apache-2.0"
+
+[[annotations]]
+path = "src/doc/embedded-book/**"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "Rust on Embedded Devices Working Group",
+    "The Rust Project Developers (see https://thanks.rust-lang.org)",
+]
+SPDX-License-Identifier = "MIT OR Apache-2.0 OR CC-BY-SA-4.0"
+
+[[annotations]]
+path = "src/doc/rust-by-example/**"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "2014 Jorge Aparicio",
+    "The Rust Project Developers (see https://thanks.rust-lang.org)",
+]
+SPDX-License-Identifier = "MIT OR Apache-2.0"
+
+[[annotations]]
+path = "src/llvm-project/**"
+precedence = "override"
+SPDX-FileCopyrightText = [
+    "2003-2019 by the contributors listed in [CREDITS.TXT](https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT)",
+    "2010 Apple Inc",
+    "2003-2019 University of Illinois at Urbana-Champaign.",
+]
+SPDX-License-Identifier = "NCSA AND Apache-2.0 WITH LLVM-exception"
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 8f7dd774207..ca0b7f2ac3a 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -120,6 +120,9 @@ ast_passes_fn_without_body =
 ast_passes_forbidden_bound =
     bounds cannot be used in this context
 
+ast_passes_forbidden_const_param =
+    late-bound const parameters cannot be used currently
+
 ast_passes_forbidden_default =
     `default` is only allowed on items in trait impls
     .label = `default` because of this
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 783bca6b695..215ccd2ab4d 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -70,6 +70,13 @@ pub struct ForbiddenBound {
 }
 
 #[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_const_param)]
+pub struct ForbiddenConstParam {
+    #[primary_span]
+    pub const_param_spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
 #[diag(ast_passes_fn_param_too_many)]
 pub struct FnParamTooMany {
     #[primary_span]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 2178b65727d..e91dfb27766 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -162,6 +162,22 @@ impl<'a> PostExpansionVisitor<'a> {
             crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
         );
 
+        // FIXME(non_lifetime_binders): Const bound params are pretty broken.
+        // Let's keep users from using this feature accidentally.
+        if self.features.non_lifetime_binders {
+            let const_param_spans: Vec<_> = params
+                .iter()
+                .filter_map(|param| match param.kind {
+                    ast::GenericParamKind::Const { .. } => Some(param.ident.span),
+                    _ => None,
+                })
+                .collect();
+
+            if !const_param_spans.is_empty() {
+                self.sess.dcx().emit_err(errors::ForbiddenConstParam { const_param_spans });
+            }
+        }
+
         for param in params {
             if !param.bounds.is_empty() {
                 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 4cd0d9cb294..cbee01f2e2d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -1,6 +1,5 @@
 use rustc_errors::Diag;
 use rustc_hir::def_id::LocalDefId;
-use rustc_infer::error_reporting::infer::nice_region_error::NiceRegionError;
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::region_constraints::Constraint;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
@@ -14,6 +13,8 @@ use rustc_middle::ty::RegionVid;
 use rustc_middle::ty::UniverseIndex;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
+use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index a4fd00efe05..b147567001d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -35,8 +35,8 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, Symbol};
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
 use std::iter;
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index f97459d16ba..d505d9c004e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -27,7 +27,7 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Spanned;
 use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx};
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{
     type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 26b0d23b166..a7bf6d636c1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -16,7 +16,7 @@ use rustc_middle::{
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{sym, BytePos, DesugaringKind, Span};
 use rustc_target::abi::FieldIdx;
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits;
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 6cf797b4761..6b7bd7dc0d8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -10,11 +10,6 @@ use rustc_hir::GenericBound::Trait;
 use rustc_hir::QPath::Resolved;
 use rustc_hir::WherePredicate::BoundPredicate;
 use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
-use rustc_infer::error_reporting::infer::nice_region_error::{
-    self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
-    HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
-};
-use rustc_infer::error_reporting::infer::region::unexpected_hidden_region_diagnostic;
 use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
 use rustc_middle::bug;
 use rustc_middle::hir::place::PlaceBase;
@@ -25,6 +20,12 @@ use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_middle::ty::{Region, TyCtxt};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
+use rustc_trait_selection::error_reporting::infer::nice_region_error::{
+    self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
+    HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
+};
+use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 356416d1a75..6443c5e92e8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -14,6 +14,7 @@ use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 
 use crate::{universal_regions::DefiningTy, MirBorrowckCtxt};
 
@@ -457,8 +458,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
     ) -> RegionNameHighlight {
         let mut highlight = RegionHighlightMode::default();
         highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter);
-        let type_name =
-            self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
+        let type_name = self
+            .infcx
+            .err_ctxt()
+            .extract_inference_diagnostics_data(ty.into(), Some(highlight))
+            .name;
 
         debug!(
             "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
@@ -872,8 +876,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
 
         let mut highlight = RegionHighlightMode::default();
         highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap());
-        let type_name =
-            self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
+        let type_name = self
+            .infcx
+            .err_ctxt()
+            .extract_inference_diagnostics_data(yield_ty.into(), Some(highlight))
+            .name;
 
         let yield_span = match tcx.hir_node(self.mir_hir_id()) {
             hir::Node::Expr(hir::Expr {
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index c0e91ce32e3..cf28ba224d6 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_span::Span;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 431a704687d..e4c2e0fced7 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -11,7 +11,7 @@ use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
 use rustc_span::{ErrorGuaranteed, Span};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::solve::deeply_normalize;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 97e2344ff30..f6b54335829 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -38,7 +38,44 @@ pub(crate) fn expand_deriving_const_param_ty(
 ) {
     let trait_def = TraitDef {
         span,
-        path: path_std!(marker::ConstParamTy),
+        path: path_std!(marker::ConstParamTy_),
+        skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: false,
+        additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
+        supports_unions: false,
+        methods: Vec::new(),
+        associated_types: Vec::new(),
+        is_const,
+    };
+
+    trait_def.expand(cx, mitem, item, push);
+
+    let trait_def = TraitDef {
+        span,
+        path: path_std!(marker::UnsizedConstParamTy),
+        skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: false,
+        additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
+        supports_unions: false,
+        methods: Vec::new(),
+        associated_types: Vec::new(),
+        is_const,
+    };
+
+    trait_def.expand(cx, mitem, item, push);
+}
+
+pub(crate) fn expand_deriving_unsized_const_param_ty(
+    cx: &ExtCtxt<'_>,
+    span: Span,
+    mitem: &MetaItem,
+    item: &Annotatable,
+    push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
+) {
+    let trait_def = TraitDef {
+        span,
+        path: path_std!(marker::UnsizedConstParamTy),
         skip_path_as_bound: false,
         needs_copy_as_bound_if_packed: false,
         additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index f8d93666145..c77ff9eb13c 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -118,6 +118,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         Clone: clone::expand_deriving_clone,
         Copy: bounds::expand_deriving_copy,
         ConstParamTy: bounds::expand_deriving_const_param_ty,
+        UnsizedConstParamTy: bounds::expand_deriving_unsized_const_param_ty,
         Debug: debug::expand_deriving_debug,
         Default: default::expand_deriving_default,
         Eq: eq::expand_deriving_eq,
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index eb21e027dd0..3b3c86a1bd1 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -70,7 +70,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system
 |FreeBSD|✅[^no-rustup]|❓|❓|❓|
 |AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]|
 |Other unixes|❓|❓|❓|❓|
-|macOS|✅|✅[^no-rustup]|N/A|N/A|
+|macOS|✅|✅|N/A|N/A|
 |Windows|✅[^no-rustup]|❌|N/A|N/A|
 
 ✅: Fully supported and tested
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index ac5aaea561c..24cf3f061a5 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -10,12 +10,12 @@ use std::mem;
 use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
 use cranelift_codegen::isa::CallConv;
 use cranelift_module::ModuleError;
+use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::TypeVisitableExt;
-use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 use rustc_target::abi::call::{Conv, FnAbi, PassMode};
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 5adbbb09ac8..9bc7b57c537 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -5,13 +5,13 @@ use cranelift_codegen::CodegenError;
 use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
 use cranelift_module::ModuleError;
 use rustc_ast::InlineAsmOptions;
+use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::TypeVisitableExt;
-use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
 
 use crate::constant::ConstantCx;
 use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 192e6c91ea3..8d3d5ac98e1 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -24,7 +24,6 @@ extern crate rustc_hir;
 extern crate rustc_incremental;
 extern crate rustc_index;
 extern crate rustc_metadata;
-extern crate rustc_monomorphize;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index e7669470026..3877460fcdb 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -271,6 +271,17 @@ fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     Some(sspattr.create_attr(cx.llcx))
 }
 
+fn backchain_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
+    if cx.sess().target.arch != "s390x" {
+        return None;
+    }
+
+    let requested_features = cx.sess().opts.cg.target_feature.split(',');
+    let found_positive = requested_features.clone().any(|r| r == "+backchain");
+
+    if found_positive { Some(llvm::CreateAttrString(cx.llcx, "backchain")) } else { None }
+}
+
 pub fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute {
     let target_cpu = llvm_util::target_cpu(cx.tcx.sess);
     llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
@@ -447,6 +458,9 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     if let Some(align) = codegen_fn_attrs.alignment {
         llvm::set_alignment(llfn, align);
     }
+    if let Some(backchain) = backchain_attr(cx) {
+        to_add.push(backchain);
+    }
     to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
     to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry));
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 98dc8ac86d2..4d56d1d3b1a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -14,7 +14,7 @@ use rustc_session::config::{PrintKind, PrintRequest};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
-use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
+use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
 
 use std::ffi::{c_char, c_void, CStr, CString};
 use std::fmt::Write;
@@ -321,6 +321,10 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
             }
         })
         .filter(|feature| {
+            // skip checking special features, as LLVM may not understands them
+            if RUSTC_SPECIAL_FEATURES.contains(feature) {
+                return true;
+            }
             // check that all features in a given smallvec are enabled
             for llvm_feature in to_llvm_features(sess, feature) {
                 let cstr = SmallCStr::new(llvm_feature);
@@ -546,6 +550,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
 
     // -Ctarget-features
     let supported_features = sess.target.supported_target_features();
+    let (llvm_major, _, _) = get_version();
     let mut featsmap = FxHashMap::default();
     let feats = sess
         .opts
@@ -604,6 +609,13 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
             if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
                 return None;
             }
+
+            // if the target-feature is "backchain" and LLVM version is greater than 18
+            // then we also need to add "+backchain" to the target-features attribute.
+            // otherwise, we will only add the naked `backchain` attribute to the attribute-group.
+            if feature == "backchain" && llvm_major < 18 {
+                return None;
+            }
             // ... otherwise though we run through `to_llvm_features` when
             // passing requests down to LLVM. This means that all in-language
             // features also work on the command line instead of having two
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 137f14fe706..399ac485850 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -806,6 +806,34 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
     ongoing_codegen
 }
 
+/// Returns whether a call from the current crate to the [`Instance`] would produce a call
+/// from `compiler_builtins` to a symbol the linker must resolve.
+///
+/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
+/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
+/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
+/// unlinkable calls.
+///
+/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
+pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+) -> bool {
+    fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
+            name.as_str().starts_with("llvm.")
+        } else {
+            false
+        }
+    }
+
+    let def_id = instance.def_id();
+    !def_id.is_local()
+        && tcx.is_compiler_builtins(LOCAL_CRATE)
+        && !is_llvm_intrinsic(tcx, def_id)
+        && !tcx.should_codegen_locally(instance)
+}
+
 impl CrateInfo {
     pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
         let crate_types = tcx.crate_types().to_vec();
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 6a5525dc2b3..c9c8f02c491 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -3,7 +3,7 @@ use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized};
 use super::place::{PlaceRef, PlaceValue};
 use super::{CachedLlbb, FunctionCx, LocalRef};
 
-use crate::base;
+use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
 use crate::common::{self, IntPredicate};
 use crate::errors::CompilerBuiltinsCannotCall;
 use crate::meth;
@@ -18,7 +18,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
-use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_session::config::OptLevel;
 use rustc_span::{source_map::Spanned, sym, Span};
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index cea164df617..e7cee5220d6 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -82,6 +82,7 @@ pub fn from_target_feature(
                 Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
                 Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
                 Some(sym::xop_target_feature) => rust_features.xop_target_feature,
+                Some(sym::s390x_target_feature) => rust_features.s390x_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 523d55fe2d0..8700ec4c210 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
 use rustc_middle::ty::{Instance, InstanceKind, TypeVisitableExt};
 use rustc_mir_dataflow::Analysis;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0771.md b/compiler/rustc_error_codes/src/error_codes/E0771.md
index 4f36590025b..74149eb79f6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0771.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0771.md
@@ -6,7 +6,7 @@ allowed.
 Erroneous code example:
 
 ```compile_fail,E0770
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 fn function_with_str<'a, const STRING: &'a str>() {} // error!
 ```
@@ -15,7 +15,7 @@ To fix this issue, the lifetime in the const generic need to be changed to
 `'static`:
 
 ```
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 fn function_with_str<const STRING: &'static str>() {} // ok!
 ```
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 56ef609612a..4b730d307fd 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -352,10 +352,10 @@ fn check_occurrences(
             check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name);
         }
         TokenTree::MetaVarExpr(dl, ref mve) => {
-            let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else {
-                return;
-            };
-            check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
+            mve.for_each_metavar((), |_, ident| {
+                let name = MacroRulesNormalizedIdent::new(*ident);
+                check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
+            });
         }
         TokenTree::Delimited(.., ref del) => {
             check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar);
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 2964ac8cc58..c4ba98f581e 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -111,10 +111,18 @@ impl MetaVarExpr {
         Ok(rslt)
     }
 
-    pub(crate) fn ident(&self) -> Option<Ident> {
-        match *self {
-            MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
-            MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None,
+    pub(crate) fn for_each_metavar<A>(&self, mut aux: A, mut cb: impl FnMut(A, &Ident) -> A) -> A {
+        match self {
+            MetaVarExpr::Concat(elems) => {
+                for elem in elems {
+                    if let MetaVarExprConcatElem::Var(ident) = elem {
+                        aux = cb(aux, ident)
+                    }
+                }
+                aux
+            }
+            MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => cb(aux, ident),
+            MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => aux,
         }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 7e2ea8de5fc..62337756cd8 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -557,17 +557,13 @@ fn lockstep_iter_size(
             }
         }
         TokenTree::MetaVarExpr(_, expr) => {
-            let default_rslt = LockstepIterSize::Unconstrained;
-            let Some(ident) = expr.ident() else {
-                return default_rslt;
-            };
-            let name = MacroRulesNormalizedIdent::new(ident);
-            match lookup_cur_matched(name, interpolations, repeats) {
-                Some(MatchedSeq(ads)) => {
-                    default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
-                }
-                _ => default_rslt,
-            }
+            expr.for_each_metavar(LockstepIterSize::Unconstrained, |lis, ident| {
+                lis.with(lockstep_iter_size(
+                    &TokenTree::MetaVar(ident.span, *ident),
+                    interpolations,
+                    repeats,
+                ))
+            })
         }
         TokenTree::Token(..) => LockstepIterSize::Unconstrained,
     }
@@ -695,7 +691,23 @@ fn transcribe_metavar_expr<'a>(
                 let symbol = match element {
                     MetaVarExprConcatElem::Ident(elem) => elem.name,
                     MetaVarExprConcatElem::Literal(elem) => *elem,
-                    MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?,
+                    MetaVarExprConcatElem::Var(ident) => {
+                        match matched_from_ident(dcx, *ident, interp)? {
+                            NamedMatch::MatchedSeq(named_matches) => {
+                                let curr_idx = repeats.last().unwrap().0;
+                                match &named_matches[curr_idx] {
+                                    // FIXME(c410-f3r) Nested repetitions are unimplemented
+                                    MatchedSeq(_) => unimplemented!(),
+                                    MatchedSingle(pnr) => {
+                                        extract_symbol_from_pnr(dcx, pnr, ident.span)?
+                                    }
+                                }
+                            }
+                            NamedMatch::MatchedSingle(pnr) => {
+                                extract_symbol_from_pnr(dcx, pnr, ident.span)?
+                            }
+                        }
+                    }
                 };
                 concatenated.push_str(symbol.as_str());
             }
@@ -752,41 +764,48 @@ fn transcribe_metavar_expr<'a>(
 }
 
 /// Extracts an metavariable symbol that can be an identifier, a token tree or a literal.
-fn extract_var_symbol<'a>(
+fn extract_symbol_from_pnr<'a>(
     dcx: DiagCtxtHandle<'a>,
-    ident: Ident,
-    interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
+    pnr: &ParseNtResult,
+    span_err: Span,
 ) -> PResult<'a, Symbol> {
-    if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? {
-        if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
+    match pnr {
+        ParseNtResult::Ident(nt_ident, is_raw) => {
             if let IdentIsRaw::Yes = is_raw {
-                return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
+                return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR));
             }
             return Ok(nt_ident.name);
         }
-
-        if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr {
-            if let TokenKind::Ident(symbol, is_raw) = kind {
-                if let IdentIsRaw::Yes = is_raw {
-                    return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
-                }
-                return Ok(*symbol);
-            }
-
-            if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind {
-                return Ok(*symbol);
+        ParseNtResult::Tt(TokenTree::Token(
+            Token { kind: TokenKind::Ident(symbol, is_raw), .. },
+            _,
+        )) => {
+            if let IdentIsRaw::Yes = is_raw {
+                return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR));
             }
+            return Ok(*symbol);
         }
-
-        if let ParseNtResult::Nt(nt) = pnr
-            && let Nonterminal::NtLiteral(expr) = &**nt
-            && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind
+        ParseNtResult::Tt(TokenTree::Token(
+            Token {
+                kind: TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }),
+                ..
+            },
+            _,
+        )) => {
+            return Ok(*symbol);
+        }
+        ParseNtResult::Nt(nt)
+            if let Nonterminal::NtLiteral(expr) = &**nt
+                && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) =
+                    &expr.kind =>
         {
             return Ok(*symbol);
         }
+        _ => Err(dcx
+            .struct_err(
+                "metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`",
+            )
+            .with_note("currently only string literals are supported")
+            .with_span(span_err)),
     }
-    Err(dcx
-        .struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`")
-        .with_note("currently only string literals are supported")
-        .with_span(ident.span))
 }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 1db3774222a..9b5ed3b0876 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -312,6 +312,7 @@ declare_features! (
     (unstable, prfchw_target_feature, "1.78.0", Some(44839)),
     (unstable, riscv_target_feature, "1.45.0", Some(44839)),
     (unstable, rtm_target_feature, "1.35.0", Some(44839)),
+    (unstable, s390x_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
     (unstable, sse4a_target_feature, "1.27.0", Some(44839)),
     (unstable, tbm_target_feature, "1.27.0", Some(44839)),
     (unstable, wasm_target_feature, "1.30.0", Some(44839)),
@@ -339,8 +340,8 @@ declare_features! (
     (unstable, abi_riscv_interrupt, "1.73.0", Some(111889)),
     /// Allows `extern "x86-interrupt" fn()`.
     (unstable, abi_x86_interrupt, "1.17.0", Some(40180)),
-    /// Allows additional const parameter types, such as `&'static str` or user defined types
-    (incomplete, adt_const_params, "1.56.0", Some(95174)),
+    /// Allows additional const parameter types, such as `[u8; 10]` or user defined types
+    (unstable, adt_const_params, "1.56.0", Some(95174)),
     /// Allows defining an `#[alloc_error_handler]`.
     (unstable, alloc_error_handler, "1.29.0", Some(51540)),
     /// Allows trait methods with arbitrary self types.
@@ -630,6 +631,9 @@ declare_features! (
     (unstable, unsafe_attributes, "1.80.0", Some(123757)),
     /// Allows unsafe on extern declarations and safety qualifiers over internal items.
     (unstable, unsafe_extern_blocks, "1.80.0", Some(123743)),
+    /// Allows const generic parameters to be defined with types that
+    /// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
+    (incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)),
     /// Allows unsized fn parameters.
     (internal, unsized_fn_params, "1.49.0", Some(48055)),
     /// Allows unsized rvalues at arguments and parameters.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 30c0e40206a..58cc0f62111 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -358,6 +358,7 @@ language_item_table! {
     PointerLike,             sym::pointer_like,        pointer_like,               Target::Trait,          GenericRequirement::Exact(0);
 
     ConstParamTy,            sym::const_param_ty,      const_param_ty_trait,       Target::Trait,          GenericRequirement::Exact(0);
+    UnsizedConstParamTy,     sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
 
     Poll,                    sym::Poll,                poll,                       Target::Enum,           GenericRequirement::None;
     PollReady,               sym::Ready,               poll_ready_variant,         Target::Variant,        GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index f08a0f8c8fc..cc404daa51f 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -99,6 +99,10 @@ hir_analysis_const_param_ty_impl_on_non_adt =
     the trait `ConstParamTy` may not be implemented for this type
     .label = type is not a structure or enumeration
 
+hir_analysis_const_param_ty_impl_on_unsized =
+    the trait `ConstParamTy` may not be implemented for this type
+    .label = type is not `Sized`
+
 hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
 
 hir_analysis_copy_impl_on_non_adt =
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index dbc265ad3ff..27db5418165 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -26,7 +26,7 @@ use rustc_middle::ty::{
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_type_ir::fold::TypeFoldable;
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 6c53625b590..c99f13468e2 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::{
 use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index ce921f64481..e4d4b7df24e 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -7,7 +7,7 @@ use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::ops::Not;
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 24aeb024461..4c230ad84de 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -82,7 +82,6 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::BitSet;
-use rustc_infer::error_reporting::infer::ObligationCauseExt as _;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, TyCtxtInferExt as _};
 use rustc_infer::traits::ObligationCause;
@@ -96,10 +95,9 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::error_reporting::traits::suggestions::{
-    ReturnsVisitor, TypeErrCtxtExt as _,
-};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
+use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::errors;
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 71a7b0b1638..0316ef69bf8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -29,7 +29,7 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
@@ -922,10 +922,8 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
         } => {
             let ty = tcx.type_of(param.def_id).instantiate_identity();
 
-            if tcx.features().adt_const_params {
+            if tcx.features().unsized_const_params {
                 enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
-                    let trait_def_id =
-                        tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span));
                     wfcx.register_bound(
                         ObligationCause::new(
                             hir_ty.span,
@@ -934,7 +932,21 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                         ),
                         wfcx.param_env,
                         ty,
-                        trait_def_id,
+                        tcx.require_lang_item(LangItem::UnsizedConstParamTy, Some(hir_ty.span)),
+                    );
+                    Ok(())
+                })
+            } else if tcx.features().adt_const_params {
+                enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
+                    wfcx.register_bound(
+                        ObligationCause::new(
+                            hir_ty.span,
+                            param.def_id,
+                            ObligationCauseCode::ConstParam(ty),
+                        ),
+                        wfcx.param_env,
+                        ty,
+                        tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)),
                     );
                     Ok(())
                 })
@@ -958,14 +970,29 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                 diag.note("the only supported types are integers, `bool` and `char`");
 
                 let cause = ObligationCause::misc(hir_ty.span, param.def_id);
+                let adt_const_params_feature_string =
+                    " more complex and user defined types".to_string();
                 let may_suggest_feature = match type_allowed_to_implement_const_param_ty(
                     tcx,
                     tcx.param_env(param.def_id),
                     ty,
+                    LangItem::ConstParamTy,
                     cause,
                 ) {
                     // Can never implement `ConstParamTy`, don't suggest anything.
-                    Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
+                    Err(
+                        ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed
+                        | ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(..),
+                    ) => None,
+                    Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
+                        Some(vec![
+                            (adt_const_params_feature_string, sym::adt_const_params),
+                            (
+                                " references to implement the `ConstParamTy` trait".into(),
+                                sym::unsized_const_params,
+                            ),
+                        ])
+                    }
                     // May be able to implement `ConstParamTy`. Only emit the feature help
                     // if the type is local, since the user may be able to fix the local type.
                     Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
@@ -985,20 +1012,16 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                             }
                         }
 
-                        ty_is_local(ty)
+                        ty_is_local(ty).then_some(vec![(
+                            adt_const_params_feature_string,
+                            sym::adt_const_params,
+                        )])
                     }
                     // Implments `ConstParamTy`, suggest adding the feature to enable.
-                    Ok(..) => true,
+                    Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]),
                 };
-                if may_suggest_feature {
-                    tcx.disabled_nightly_features(
-                        &mut diag,
-                        Some(param.hir_id),
-                        [(
-                            " more complex and user defined types".to_string(),
-                            sym::adt_const_params,
-                        )],
-                    );
+                if let Some(features) = may_suggest_feature {
+                    tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features);
                 }
 
                 Err(diag.emit())
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 2ecb170ec89..b35ee270fef 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
     ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
@@ -36,9 +36,13 @@ pub(super) fn check_trait<'tcx>(
     let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
     let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
     res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
-    res = res.and(
-        checker.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty),
-    );
+    res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| {
+        visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
+    }));
+    res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
+        visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
+    }));
+
     res = res.and(
         checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
     );
@@ -103,7 +107,13 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
         Ok(()) => Ok(()),
         Err(CopyImplementationError::InfringingFields(fields)) => {
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
-            Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span))
+            Err(infringing_fields_error(
+                tcx,
+                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
+                LangItem::Copy,
+                impl_did,
+                span,
+            ))
         }
         Err(CopyImplementationError::NotAnAdt) => {
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
@@ -116,7 +126,12 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
     }
 }
 
-fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
+fn visit_implementation_of_const_param_ty(
+    checker: &Checker<'_>,
+    kind: LangItem,
+) -> Result<(), ErrorGuaranteed> {
+    assert!(matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy));
+
     let tcx = checker.tcx;
     let header = checker.impl_header;
     let impl_did = checker.impl_def_id;
@@ -125,21 +140,41 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E
 
     let param_env = tcx.param_env(impl_did);
 
-    if let ty::ImplPolarity::Negative = header.polarity {
+    if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
         return Ok(());
     }
 
     let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
-    match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
+    match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) {
         Ok(()) => Ok(()),
         Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
-            Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span))
+            Err(infringing_fields_error(
+                tcx,
+                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
+                LangItem::ConstParamTy,
+                impl_did,
+                span,
+            ))
         }
         Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
         }
+        Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
+            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            Err(infringing_fields_error(
+                tcx,
+                infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
+                LangItem::ConstParamTy,
+                impl_did,
+                span,
+            ))
+        }
+        Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
+            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
+        }
     }
 }
 
@@ -501,9 +536,9 @@ pub fn coerce_unsized_info<'tcx>(
     Ok(CoerceUnsizedInfo { custom_kind: kind })
 }
 
-fn infringing_fields_error(
-    tcx: TyCtxt<'_>,
-    fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
+fn infringing_fields_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
     lang_item: LangItem,
     impl_did: LocalDefId,
     impl_span: Span,
@@ -521,13 +556,13 @@ fn infringing_fields_error(
 
     let mut label_spans = Vec::new();
 
-    for (field, ty, reason) in fields {
+    for (span, ty, reason) in infringing_tys {
         // Only report an error once per type.
         if !seen_tys.insert(ty) {
             continue;
         }
 
-        label_spans.push(tcx.def_span(field.did));
+        label_spans.push(span);
 
         match reason {
             InfringingFieldsReason::Fulfill(fulfillment_errors) => {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 16f72f38d60..f2804ce31fa 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -517,9 +517,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
         if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
             return;
         }
-        let Some(origin) = self.infcx.type_var_origin(ty) else {
+        let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
             return ty.super_visit_with(self);
         };
+        let origin = self.infcx.type_var_origin(vid);
         if let Some(def_id) = origin.param_def_id {
             self.uncovered_params.insert(def_id);
         }
@@ -546,9 +547,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> {
         if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
             return ty;
         }
-        let Some(origin) = self.infcx.type_var_origin(ty) else {
+        let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
             return ty.super_fold_with(self);
         };
+        let origin = self.infcx.type_var_origin(vid);
         if let Some(def_id) = origin.param_def_id {
             // The generics of an `impl` don't have a parent, we can index directly.
             let index = self.generics.param_def_id_to_index[&def_id];
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 7930f54038d..349dc9ad00e 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -2094,11 +2094,7 @@ pub fn deny_non_region_late_bound(
             format!("late-bound {what} parameter not allowed on {where_}"),
         );
 
-        let guar = if tcx.features().non_lifetime_binders && first {
-            diag.emit()
-        } else {
-            diag.delay_as_bug()
-        };
+        let guar = diag.emit_unless(!tcx.features().non_lifetime_binders || !first);
 
         first = false;
         *arg = ResolvedArg::Error(guar);
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 2eca64c27d0..c83788928a9 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -279,6 +279,14 @@ pub struct CopyImplOnNonAdt {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_analysis_const_param_ty_impl_on_unsized)]
+pub struct ConstParamTyImplOnUnsized {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
 pub struct ConstParamTyImplOnNonAdt {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 5b8b6e98125..2e5f99bb78b 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -78,7 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_span::{ErrorGuaranteed, Span};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt};
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 5e2a68e1f02..1bfe9734217 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -58,8 +58,6 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtSelectionErrExt as _;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index d708269f1f5..0d002c52fbb 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -53,8 +53,6 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
@@ -2574,7 +2572,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base: &'tcx hir::Expr<'tcx>,
         ty: Ty<'tcx>,
     ) {
-        let Some(output_ty) = self.get_impl_future_output_ty(ty) else {
+        let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else {
             err.span_label(field_ident.span, "unknown field");
             return;
         };
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 3cecbfd4275..9f3aeacd2c5 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -175,7 +175,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         };
         debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
 
-        let span = self.infcx.type_var_origin(ty).map(|origin| origin.span).unwrap_or(DUMMY_SP);
+        let span = ty.ty_vid().map_or(DUMMY_SP, |vid| self.infcx.type_var_origin(vid).span);
         self.demand_eqtype(span, ty, fallback);
         self.fallback_has_occurred.set(true);
         true
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index cc2c1a302f5..87e8afe6dd1 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -19,7 +19,6 @@ use rustc_hir_analysis::hir_ty_lowering::{
     GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
 };
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
-use rustc_infer::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
 use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@@ -37,7 +36,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use rustc_target::abi::FieldIdx;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_trait_selection::traits::{
     self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt,
 };
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index f7abba35706..8e35efa53ae 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -338,8 +338,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindAmbiguousParameter<'_, 'tcx> {
             type Result = ControlFlow<ty::GenericArg<'tcx>>;
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-                if let Some(origin) = self.0.type_var_origin(ty)
-                    && let Some(def_id) = origin.param_def_id
+                if let ty::Infer(ty::TyVar(vid)) = *ty.kind()
+                    && let Some(def_id) = self.0.type_var_origin(vid).param_def_id
                     && let generics = self.0.tcx.generics_of(self.1)
                     && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
                     && let Some(arg) =
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 2b4025ca808..7c96a991bed 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -29,7 +29,6 @@ use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
 use rustc_hir_analysis::check::potentially_plural_count;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_index::IndexVec;
-use rustc_infer::error_reporting::infer::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::TypeTrace;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
@@ -39,6 +38,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 3fe87c03e74..39d73dae015 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -15,13 +15,13 @@ use hir::def_id::CRATE_DEF_ID;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
-use rustc_infer::error_reporting::infer::sub_relations::SubRelations;
-use rustc_infer::error_reporting::infer::TypeErrCtxt;
 use rustc_infer::infer;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::{self, sym, Span, DUMMY_SP};
+use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
+use rustc_trait_selection::error_reporting::TypeErrCtxt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
 
 use std::cell::{Cell, RefCell};
@@ -162,9 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Creates an `TypeErrCtxt` with a reference to the in-progress
     /// `TypeckResults` which is used for diagnostics.
-    /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
+    /// Use [`InferCtxtErrorExt::err_ctxt`] to start one without a `TypeckResults`.
     ///
-    /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
+    /// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt
     pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
         let mut sub_relations = SubRelations::default();
         sub_relations.add_constraints(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index b3b4c5a56fb..fe7495deb2b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -32,8 +32,8 @@ use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, Symbol};
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::error_reporting::traits::DefIdOrName;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -1107,12 +1107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .tcx
                     .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars));
                 let ty = match self.tcx.asyncness(fn_id) {
-                    ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
-                        span_bug!(
-                            fn_decl.output.span(),
-                            "failed to get output type of async function"
-                        )
-                    }),
+                    ty::Asyncness::Yes => {
+                        self.err_ctxt().get_impl_future_output_ty(ty).unwrap_or_else(|| {
+                            span_bug!(
+                                fn_decl.output.span(),
+                                "failed to get output type of async function"
+                            )
+                        })
+                    }
                     ty::Asyncness::No => ty,
                 };
                 let ty = self.normalize(expr.span, ty);
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index e817685e41c..9cb6124ab21 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -12,7 +12,6 @@ use rustc_hir::HirId;
 use rustc_hir_analysis::autoderef::{self, Autoderef};
 use rustc_infer::infer::canonical::OriginalQueryValues;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
-use rustc_infer::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCauseCode;
@@ -34,6 +33,7 @@ use rustc_span::edit_distance::{
 };
 use rustc_span::symbol::sym;
 use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 9bb30780a6e..da3ac2fea98 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -36,7 +36,6 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span};
 use rustc_span::{Symbol, DUMMY_SP};
 use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote;
-use rustc_trait_selection::error_reporting::traits::on_unimplemented::TypeErrCtxtExt as _;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
@@ -3276,7 +3275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         return_type: Option<Ty<'tcx>>,
     ) {
-        let output_ty = match self.get_impl_future_output_ty(ty) {
+        let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) {
             Some(output_ty) => self.resolve_vars_if_possible(output_ty),
             _ => return,
         };
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index d59b8276d3a..7b5845388d4 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -18,7 +18,6 @@ use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
 use rustc_type_ir::TyKind::*;
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 611854ce2af..4ef7f37b309 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -8,7 +8,6 @@ use rustc_errors::{ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirId;
-use rustc_infer::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_middle::span_bug;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -18,7 +17,7 @@ use rustc_middle::ty::TypeSuperFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_trait_selection::solve;
 
 use std::mem;
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index c279195a7e9..e51734ff7a7 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -1,397 +1,5 @@
-infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
-    [true] , for some specific lifetime `'{$lifetime}`
-    *[false] {""}
-}
-infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
-    [true] , for some specific lifetime `'{$lifetime}`
-    *[false] {""}
-}
-infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
-    [true] , for some specific lifetime `'{$lifetime}`
-    *[false] {""}
-}
-
-infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`
-
-infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
-infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
-infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_ascribe_user_type_prove_predicate = ...so that the where clause holds
-
-infer_await_both_futures = consider `await`ing on both `Future`s
-infer_await_future = consider `await`ing on the `Future`
-infer_await_note = calling an async function returns a future
-
-infer_but_calling_introduces = {$has_param_name ->
-    [true] `{$param_name}`
-    *[false] `fn` parameter
-} has {$lifetime_kind ->
-    [true] lifetime `{$lifetime}`
-    *[false] an anonymous lifetime `'_`
-} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement
-    .label1 = {$has_lifetime ->
-        [true] lifetime `{$lifetime}`
-        *[false] an anonymous lifetime `'_`
-    }
-    .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
-        [true] `impl` of `{$impl_path}`
-        *[false] inherent `impl`
-    }
-
-infer_but_needs_to_satisfy = {$has_param_name ->
-    [true] `{$param_name}`
-    *[false] `fn` parameter
-} has {$has_lifetime ->
-    [true] lifetime `{$lifetime}`
-    *[false] an anonymous lifetime `'_`
-} but it needs to satisfy a `'static` lifetime requirement
-    .influencer = this data with {$has_lifetime ->
-        [true] lifetime `{$lifetime}`
-        *[false] an anonymous lifetime `'_`
-    }...
-    .require = {$spans_empty ->
-        *[true] ...is used and required to live as long as `'static` here
-        [false] ...and is required to live as long as `'static` here
-    }
-    .used_here = ...is used here...
-    .introduced_by_bound = `'static` lifetime requirement introduced by this bound
-
-infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
-infer_consider_specifying_length = consider specifying the actual array length
-infer_data_flows = ...but data{$label_var1_exists ->
-    [true] {" "}from `{$label_var1}`
-    *[false] {""}
-} flows{$label_var2_exists ->
-    [true] {" "}into `{$label_var2}`
-    *[false] {""}
-} here
-
-infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
-infer_data_returned = ...but data{$label_var1_exists ->
-    [true] {" "}from `{$label_var1}`
-    *[false] {""}
-} is returned here
-
-infer_declared_different = this parameter and the return type are declared with different lifetimes...
-infer_declared_multiple = this type is declared with multiple lifetimes...
-infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
-infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
-infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
-infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
-infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
-
-infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
-
-infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
-
-infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
-    .label = lifetime `{$named}` required
-
-infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
-    .label = lifetime `{$named}` required
-
-infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
-
-infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
-infer_fps_cast = consider casting to a fn pointer
-infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
-
-infer_fps_items_are_distinct = fn items are distinct from fn pointers
-infer_fps_remove_ref = consider removing the reference
-infer_fps_use_ref = consider using a reference
-infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
-
-infer_full_type_written = the full type name has been written to '{$path}'
-
-infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
-infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
-infer_label_bad = {$bad_kind ->
-    *[other] cannot infer type
-    [more_info] cannot infer {$prefix_kind ->
-        *[type] type for {$prefix}
-        [const_with_param] the value of const parameter
-        [const] the value of the constant
-    } `{$name}`{$has_parent ->
-        [true] {" "}declared on the {$parent_prefix} `{$parent_name}`
-        *[false] {""}
-    }
-}
-
-infer_lf_bound_not_satisfied = lifetime bound not satisfied
-infer_lifetime_mismatch = lifetime mismatch
-
-infer_lifetime_param_suggestion = consider {$is_reuse ->
-    [true] reusing
-    *[false] introducing
-} a named lifetime parameter{$is_impl ->
-    [true] {" "}and update trait if needed
-    *[false] {""}
-}
-infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
-
-infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
-infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
-infer_meant_str_literal = if you meant to write a string literal, use double quotes
-infer_mismatched_static_lifetime = incompatible lifetime on type
-infer_more_targeted = {$has_param_name ->
-    [true] `{$param_name}`
-    *[false] `fn` parameter
-} has {$has_lifetime ->
-    [true] lifetime `{$lifetime}`
-    *[false] an anonymous lifetime `'_`
-} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
-
-infer_msl_introduces_static = introduces a `'static` lifetime requirement
-infer_msl_unmet_req = because this has an unmet lifetime requirement
-
-infer_nothing = {""}
-
-infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
-infer_oc_closure_selfref = closure/coroutine type that references itself
-infer_oc_const_compat = const not compatible with trait
-infer_oc_fn_lang_correct_type = {$lang_item_name ->
-        [panic_impl] `#[panic_handler]`
-        *[lang_item_name] lang item `{$lang_item_name}`
-    } function has wrong type
-infer_oc_fn_main_correct_type = `main` function has wrong type
-infer_oc_fn_start_correct_type = `#[start]` function has wrong type
-infer_oc_generic = mismatched types
-
-infer_oc_if_else_different = `if` and `else` have incompatible types
-infer_oc_intrinsic_correct_type = intrinsic has wrong type
-infer_oc_match_compat = `match` arms have incompatible types
-infer_oc_method_compat = method not compatible with trait
-infer_oc_method_correct_type = mismatched `self` parameter type
-infer_oc_no_diverge = `else` clause of `let...else` does not diverge
-infer_oc_no_else = `if` may be missing an `else` clause
-infer_oc_try_compat = `?` operator has incompatible types
-infer_oc_type_compat = type not compatible with trait
-infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
-    .label = opaque type defined here
-
 infer_opaque_hidden_type =
     opaque type's hidden type cannot be another opaque type from the same scope
     .label = one of the two opaque types used here has to be outside its defining scope
     .opaque_type = opaque type whose hidden type is being assigned
     .hidden_type = opaque type being used as hidden type
-
-infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
-infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
-
-infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it
-infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}`
-
-infer_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
-
-infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
-infer_prlf_defined_without_sub = the lifetime defined here...
-infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
-infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
-infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here
-infer_reborrow = ...so that reference does not outlive borrowed content
-infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
-
-infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
-infer_region_explanation = {$pref_kind ->
-    *[should_not_happen] [{$pref_kind}]
-    [ref_valid_for] ...the reference is valid for
-    [content_valid_for] ...but the borrowed content is only valid for
-    [type_obj_valid_for] object type is valid for
-    [source_pointer_valid_for] source pointer is only valid for
-    [type_satisfy] type must satisfy
-    [type_outlive] type must outlive
-    [lf_param_instantiated_with] lifetime parameter instantiated with
-    [lf_param_must_outlive] but lifetime parameter must outlive
-    [lf_instantiated_with] lifetime instantiated with
-    [lf_must_outlive] but lifetime must outlive
-    [pointer_valid_for] the pointer is valid for
-    [data_valid_for] but the referenced data is only valid for
-    [empty] {""}
-}{$pref_kind ->
-    [empty] {""}
-    *[other] {" "}
-}{$desc_kind ->
-    *[should_not_happen] [{$desc_kind}]
-    [restatic] the static lifetime
-    [revar] lifetime {$desc_arg}
-    [as_defined] the lifetime `{$desc_arg}` as defined here
-    [as_defined_anon] the anonymous lifetime as defined here
-    [defined_here] the anonymous lifetime defined here
-    [defined_here_reg] the lifetime `{$desc_arg}` as defined here
-}{$suff_kind ->
-    *[should_not_happen] [{$suff_kind}]
-    [empty]{""}
-    [continues] ...
-    [req_by_binding] {" "}as required by this binding
-}
-
-infer_relate_object_bound = ...so that it can be closed over into an object
-infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
-    [true] ...
-    *[false] {""}
-}
-infer_relate_param_bound_2 = ...that is required by this bound
-infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
-infer_ril_because_of = because of this returned expression
-infer_ril_introduced_by = requirement introduced by this return type
-infer_ril_introduced_here = `'static` requirement introduced here
-infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
-
-infer_source_kind_closure_return =
-    try giving this closure an explicit return type
-
-# coroutine_kind  may need to be translated
-infer_source_kind_fully_qualified =
-    try using a fully qualified path to specify the expected types
-
-infer_source_kind_subdiag_generic_label =
-    cannot infer {$is_type ->
-    [true] type
-    *[false] the value
-    } of the {$is_type ->
-    [true] type
-    *[false] const
-    } {$parent_exists ->
-    [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}`
-    *[false] parameter {$param_name}
-    }
-
-infer_source_kind_subdiag_generic_suggestion =
-    consider specifying the generic {$arg_count ->
-    [one] argument
-    *[other] arguments
-    }
-
-infer_source_kind_subdiag_let = {$kind ->
-    [with_pattern] consider giving `{$name}` an explicit type
-    [closure] consider giving this closure parameter an explicit type
-    *[other] consider giving this pattern a type
-}{$x_kind ->
-    [has_name] , where the {$prefix_kind ->
-        *[type] type for {$prefix}
-        [const_with_param] value of const parameter
-        [const] value of the constant
-    } `{$arg_name}` is specified
-    [underscore] , where the placeholders `_` are specified
-    *[empty] {""}
-}
-
-infer_srs_add = consider returning the local binding `{$ident}`
-infer_srs_add_one = consider returning one of these bindings
-
-infer_srs_remove = consider removing this semicolon
-infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
-infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}`
-
-infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
-infer_subtype = ...so that the {$requirement ->
-    [method_compat] method type is compatible with trait
-    [type_compat] associated type is compatible with trait
-    [const_compat] const is compatible with trait
-    [expr_assignable] expression is assignable
-    [if_else_different] `if` and `else` have incompatible types
-    [no_else] `if` missing an `else` returns `()`
-    [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
-    [fn_lang_correct_type] lang item function has the correct type
-    [intrinsic_correct_type] intrinsic has the correct type
-    [method_correct_type] method receiver has the correct type
-    *[other] types are compatible
-}
-infer_subtype_2 = ...so that {$requirement ->
-    [method_compat] method type is compatible with trait
-    [type_compat] associated type is compatible with trait
-    [const_compat] const is compatible with trait
-    [expr_assignable] expression is assignable
-    [if_else_different] `if` and `else` have incompatible types
-    [no_else] `if` missing an `else` returns `()`
-    [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
-    [fn_lang_correct_type] lang item function has the correct type
-    [intrinsic_correct_type] intrinsic has the correct type
-    [method_correct_type] method receiver has the correct type
-    *[other] types are compatible
-}
-
-infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
-
-infer_suggest_add_let_for_letchains = consider adding `let`
-
-infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
-infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
-
-infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
-infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
-    .found = found `{$found}`
-    .expected = expected `{$expected}`
-    .expected_found = expected signature `{$expected}`
-               {"   "}found signature `{$found}`
-
-infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
-    .label_satisfy = doesn't satisfy where-clause
-    .label_where = due to a where-clause on `{$def_id}`...
-    .label_dup = implementation of `{$trait_def_id}` is not general enough
-
-infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`
-
-infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element
-
-infer_type_annotations_needed = {$source_kind ->
-    [closure] type annotations needed for the closure `{$source_name}`
-    [normal] type annotations needed for `{$source_name}`
-    *[other] type annotations needed
-}
-    .label = type must be known at this point
-
-infer_types_declared_different = these two types are declared with different lifetimes...
-
-infer_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
-
-infer_where_copy_predicates = copy the `where` clause predicates from the trait
-
-infer_where_remove = remove the `where` clause
diff --git a/compiler/rustc_infer/src/error_reporting/mod.rs b/compiler/rustc_infer/src/error_reporting/mod.rs
deleted file mode 100644
index 132485ec661..00000000000
--- a/compiler/rustc_infer/src/error_reporting/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod infer;
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 2ce712e0bff..1a5c0137219 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,28 +1,5 @@
-use hir::GenericParamKind;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{
-    codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg,
-    MultiSpan, SubdiagMessageOp, Subdiagnostic,
-};
-use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::FnRetTy;
-use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
-use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt};
-use rustc_span::symbol::kw;
-use rustc_span::Symbol;
-use rustc_span::{symbol::Ident, BytePos, Span};
-
-use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted;
-use crate::error_reporting::infer::ObligationCauseAsDiagArg;
-use crate::fluent_generated as fluent;
-use crate::infer::need_type_info::UnderspecifiedArgKind;
-
-use std::path::PathBuf;
-
-pub mod note_and_explain;
+use rustc_macros::Diagnostic;
+use rustc_span::Span;
 
 #[derive(Diagnostic)]
 #[diag(infer_opaque_hidden_type)]
@@ -35,1599 +12,3 @@ pub struct OpaqueHiddenTypeDiag {
     #[note(infer_hidden_type)]
     pub hidden_type: Span,
 }
-
-#[derive(Diagnostic)]
-#[diag(infer_type_annotations_needed, code = E0282)]
-pub struct AnnotationRequired<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-    #[note(infer_full_type_written)]
-    pub was_written: Option<()>,
-    pub path: PathBuf,
-}
-
-// Copy of `AnnotationRequired` for E0283
-#[derive(Diagnostic)]
-#[diag(infer_type_annotations_needed, code = E0283)]
-pub struct AmbiguousImpl<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-    #[note(infer_full_type_written)]
-    pub was_written: Option<()>,
-    pub path: PathBuf,
-}
-
-// Copy of `AnnotationRequired` for E0284
-#[derive(Diagnostic)]
-#[diag(infer_type_annotations_needed, code = E0284)]
-pub struct AmbiguousReturn<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-    #[note(infer_full_type_written)]
-    pub was_written: Option<()>,
-    pub path: PathBuf,
-}
-
-// Used when a better one isn't available
-#[derive(Subdiagnostic)]
-#[label(infer_label_bad)]
-pub struct InferenceBadError<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub bad_kind: &'static str,
-    pub prefix_kind: UnderspecifiedArgKind,
-    pub has_parent: bool,
-    pub prefix: &'a str,
-    pub parent_prefix: &'a str,
-    pub parent_name: String,
-    pub name: String,
-}
-
-#[derive(Subdiagnostic)]
-pub enum SourceKindSubdiag<'a> {
-    #[suggestion(
-        infer_source_kind_subdiag_let,
-        style = "verbose",
-        code = ": {type_name}",
-        applicability = "has-placeholders"
-    )]
-    LetLike {
-        #[primary_span]
-        span: Span,
-        name: String,
-        type_name: String,
-        kind: &'static str,
-        x_kind: &'static str,
-        prefix_kind: UnderspecifiedArgKind,
-        prefix: &'a str,
-        arg_name: String,
-    },
-    #[label(infer_source_kind_subdiag_generic_label)]
-    GenericLabel {
-        #[primary_span]
-        span: Span,
-        is_type: bool,
-        param_name: String,
-        parent_exists: bool,
-        parent_prefix: String,
-        parent_name: String,
-    },
-    #[suggestion(
-        infer_source_kind_subdiag_generic_suggestion,
-        style = "verbose",
-        code = "::<{args}>",
-        applicability = "has-placeholders"
-    )]
-    GenericSuggestion {
-        #[primary_span]
-        span: Span,
-        arg_count: usize,
-        args: String,
-    },
-}
-
-#[derive(Subdiagnostic)]
-pub enum SourceKindMultiSuggestion<'a> {
-    #[multipart_suggestion(
-        infer_source_kind_fully_qualified,
-        style = "verbose",
-        applicability = "has-placeholders"
-    )]
-    FullyQualified {
-        #[suggestion_part(code = "{def_path}({adjustment}")]
-        span_lo: Span,
-        #[suggestion_part(code = "{successor_pos}")]
-        span_hi: Span,
-        def_path: String,
-        adjustment: &'a str,
-        successor_pos: &'a str,
-    },
-    #[multipart_suggestion(
-        infer_source_kind_closure_return,
-        style = "verbose",
-        applicability = "has-placeholders"
-    )]
-    ClosureReturn {
-        #[suggestion_part(code = "{start_span_code}")]
-        start_span: Span,
-        start_span_code: String,
-        #[suggestion_part(code = " }}")]
-        end_span: Option<Span>,
-    },
-}
-
-impl<'a> SourceKindMultiSuggestion<'a> {
-    pub fn new_fully_qualified(
-        span: Span,
-        def_path: String,
-        adjustment: &'a str,
-        successor: (&'a str, BytePos),
-    ) -> Self {
-        Self::FullyQualified {
-            span_lo: span.shrink_to_lo(),
-            span_hi: span.shrink_to_hi().with_hi(successor.1),
-            def_path,
-            adjustment,
-            successor_pos: successor.0,
-        }
-    }
-
-    pub fn new_closure_return(
-        ty_info: String,
-        data: &'a FnRetTy<'a>,
-        should_wrap_expr: Option<Span>,
-    ) -> Self {
-        let arrow = match data {
-            FnRetTy::DefaultReturn(_) => " -> ",
-            _ => "",
-        };
-        let (start_span, start_span_code, end_span) = match should_wrap_expr {
-            Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)),
-            None => (data.span(), format!("{arrow}{ty_info}"), None),
-        };
-        Self::ClosureReturn { start_span, start_span_code, end_span }
-    }
-}
-
-pub enum RegionOriginNote<'a> {
-    Plain {
-        span: Span,
-        msg: DiagMessage,
-    },
-    WithName {
-        span: Span,
-        msg: DiagMessage,
-        name: &'a str,
-        continues: bool,
-    },
-    WithRequirement {
-        span: Span,
-        requirement: ObligationCauseAsDiagArg<'a>,
-        expected_found: Option<(DiagStyledString, DiagStyledString)>,
-    },
-}
-
-impl Subdiagnostic for RegionOriginNote<'_> {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        _f: &F,
-    ) {
-        let mut label_or_note = |span, msg: DiagMessage| {
-            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
-            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
-            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
-            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
-                diag.span_label(span, msg);
-            } else if span_is_primary && expanded_sub_count == 0 {
-                diag.note(msg);
-            } else {
-                diag.span_note(span, msg);
-            }
-        };
-        match self {
-            RegionOriginNote::Plain { span, msg } => {
-                label_or_note(span, msg);
-            }
-            RegionOriginNote::WithName { span, msg, name, continues } => {
-                label_or_note(span, msg);
-                diag.arg("name", name);
-                diag.arg("continues", continues);
-            }
-            RegionOriginNote::WithRequirement {
-                span,
-                requirement,
-                expected_found: Some((expected, found)),
-            } => {
-                label_or_note(span, fluent::infer_subtype);
-                diag.arg("requirement", requirement);
-
-                diag.note_expected_found(&"", expected, &"", found);
-            }
-            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
-                // FIXME: this really should be handled at some earlier stage. Our
-                // handling of region checking when type errors are present is
-                // *terrible*.
-                label_or_note(span, fluent::infer_subtype_2);
-                diag.arg("requirement", requirement);
-            }
-        };
-    }
-}
-
-pub enum LifetimeMismatchLabels {
-    InRet {
-        param_span: Span,
-        ret_span: Span,
-        span: Span,
-        label_var1: Option<Ident>,
-    },
-    Normal {
-        hir_equal: bool,
-        ty_sup: Span,
-        ty_sub: Span,
-        span: Span,
-        sup: Option<Ident>,
-        sub: Option<Ident>,
-    },
-}
-
-impl Subdiagnostic for LifetimeMismatchLabels {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        _f: &F,
-    ) {
-        match self {
-            LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
-                diag.span_label(param_span, fluent::infer_declared_different);
-                diag.span_label(ret_span, fluent::infer_nothing);
-                diag.span_label(span, fluent::infer_data_returned);
-                diag.arg("label_var1_exists", label_var1.is_some());
-                diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
-            }
-            LifetimeMismatchLabels::Normal {
-                hir_equal,
-                ty_sup,
-                ty_sub,
-                span,
-                sup: label_var1,
-                sub: label_var2,
-            } => {
-                if hir_equal {
-                    diag.span_label(ty_sup, fluent::infer_declared_multiple);
-                    diag.span_label(ty_sub, fluent::infer_nothing);
-                    diag.span_label(span, fluent::infer_data_lifetime_flow);
-                } else {
-                    diag.span_label(ty_sup, fluent::infer_types_declared_different);
-                    diag.span_label(ty_sub, fluent::infer_nothing);
-                    diag.span_label(span, fluent::infer_data_flows);
-                    diag.arg("label_var1_exists", label_var1.is_some());
-                    diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
-                    diag.arg("label_var2_exists", label_var2.is_some());
-                    diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default());
-                }
-            }
-        }
-    }
-}
-
-pub struct AddLifetimeParamsSuggestion<'a> {
-    pub tcx: TyCtxt<'a>,
-    pub generic_param_scope: LocalDefId,
-    pub sub: Region<'a>,
-    pub ty_sup: &'a hir::Ty<'a>,
-    pub ty_sub: &'a hir::Ty<'a>,
-    pub add_note: bool,
-}
-
-impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        _f: &F,
-    ) {
-        let mut mk_suggestion = || {
-            let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
-            else {
-                return false;
-            };
-
-            let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
-            let is_impl = matches!(&node, hir::Node::ImplItem(_));
-            let (generics, parent_generics) = match node {
-                hir::Node::Item(&hir::Item {
-                    kind: hir::ItemKind::Fn(_, ref generics, ..),
-                    ..
-                })
-                | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
-                    generics,
-                    match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
-                    {
-                        hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Trait(_, _, ref generics, ..),
-                            ..
-                        })
-                        | hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
-                            ..
-                        }) => Some(generics),
-                        _ => None,
-                    },
-                ),
-                _ => return false,
-            };
-
-            let suggestion_param_name = generics
-                .params
-                .iter()
-                .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-                .map(|p| p.name.ident().name)
-                .find(|i| *i != kw::UnderscoreLifetime);
-            let introduce_new = suggestion_param_name.is_none();
-
-            let mut default = "'a".to_string();
-            if let Some(parent_generics) = parent_generics {
-                let used: FxHashSet<_> = parent_generics
-                    .params
-                    .iter()
-                    .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-                    .map(|p| p.name.ident().name)
-                    .filter(|i| *i != kw::UnderscoreLifetime)
-                    .map(|l| l.to_string())
-                    .collect();
-                if let Some(lt) =
-                    ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
-                {
-                    // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
-                    // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
-                    // likely to be an over-constraining lifetime requirement, so we always add a
-                    // lifetime to the `fn`.
-                    default = lt;
-                }
-            }
-            let suggestion_param_name =
-                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
-
-            struct ImplicitLifetimeFinder {
-                suggestions: Vec<(Span, String)>,
-                suggestion_param_name: String,
-            }
-
-            impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
-                fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
-                    let make_suggestion = |ident: Ident| {
-                        if ident.name == kw::Empty && ident.span.is_empty() {
-                            format!("{}, ", self.suggestion_param_name)
-                        } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
-                            format!("{} ", self.suggestion_param_name)
-                        } else {
-                            self.suggestion_param_name.clone()
-                        }
-                    };
-                    match ty.kind {
-                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
-                            for segment in path.segments {
-                                if let Some(args) = segment.args {
-                                    if args.args.iter().all(|arg| {
-                                        matches!(
-                                            arg,
-                                            hir::GenericArg::Lifetime(lifetime)
-                                            if lifetime.ident.name == kw::Empty
-                                        )
-                                    }) {
-                                        self.suggestions.push((
-                                            segment.ident.span.shrink_to_hi(),
-                                            format!(
-                                                "<{}>",
-                                                args.args
-                                                    .iter()
-                                                    .map(|_| self.suggestion_param_name.clone())
-                                                    .collect::<Vec<_>>()
-                                                    .join(", ")
-                                            ),
-                                        ));
-                                    } else {
-                                        for arg in args.args {
-                                            if let hir::GenericArg::Lifetime(lifetime) = arg
-                                                && lifetime.is_anonymous()
-                                            {
-                                                self.suggestions.push((
-                                                    lifetime.ident.span,
-                                                    make_suggestion(lifetime.ident),
-                                                ));
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                        hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
-                            self.suggestions
-                                .push((lifetime.ident.span, make_suggestion(lifetime.ident)));
-                        }
-                        _ => {}
-                    }
-                    walk_ty(self, ty);
-                }
-            }
-            let mut visitor = ImplicitLifetimeFinder {
-                suggestions: vec![],
-                suggestion_param_name: suggestion_param_name.clone(),
-            };
-            if let Some(fn_decl) = node.fn_decl()
-                && let hir::FnRetTy::Return(ty) = fn_decl.output
-            {
-                visitor.visit_ty(ty);
-            }
-            if visitor.suggestions.is_empty() {
-                // Do not suggest constraining the `&self` param, but rather the return type.
-                // If that is wrong (because it is not sufficient), a follow up error will tell the
-                // user to fix it. This way we lower the chances of *over* constraining, but still
-                // get the cake of "correctly" contrained in two steps.
-                visitor.visit_ty(self.ty_sup);
-            }
-            visitor.visit_ty(self.ty_sub);
-            if visitor.suggestions.is_empty() {
-                return false;
-            }
-            if introduce_new {
-                let new_param_suggestion = if let Some(first) =
-                    generics.params.iter().find(|p| !p.name.ident().span.is_empty())
-                {
-                    (first.span.shrink_to_lo(), format!("{suggestion_param_name}, "))
-                } else {
-                    (generics.span, format!("<{suggestion_param_name}>"))
-                };
-
-                visitor.suggestions.push(new_param_suggestion);
-            }
-            diag.multipart_suggestion_verbose(
-                fluent::infer_lifetime_param_suggestion,
-                visitor.suggestions,
-                Applicability::MaybeIncorrect,
-            );
-            diag.arg("is_impl", is_impl);
-            diag.arg("is_reuse", !introduce_new);
-
-            true
-        };
-        if mk_suggestion() && self.add_note {
-            diag.note(fluent::infer_lifetime_param_suggestion_elided);
-        }
-    }
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_lifetime_mismatch, code = E0623)]
-pub struct LifetimeMismatch<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub labels: LifetimeMismatchLabels,
-    #[subdiagnostic]
-    pub suggestion: AddLifetimeParamsSuggestion<'a>,
-}
-
-pub struct IntroducesStaticBecauseUnmetLifetimeReq {
-    pub unmet_requirements: MultiSpan,
-    pub binding_span: Span,
-}
-
-impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        mut self,
-        diag: &mut Diag<'_, G>,
-        _f: &F,
-    ) {
-        self.unmet_requirements
-            .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
-        diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
-    }
-}
-
-// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
-#[derive(Subdiagnostic)]
-pub enum DoesNotOutliveStaticFromImpl {
-    #[note(infer_does_not_outlive_static_from_impl)]
-    Spanned {
-        #[primary_span]
-        span: Span,
-    },
-    #[note(infer_does_not_outlive_static_from_impl)]
-    Unspanned,
-}
-
-#[derive(Subdiagnostic)]
-pub enum ImplicitStaticLifetimeSubdiag {
-    #[note(infer_implicit_static_lifetime_note)]
-    Note {
-        #[primary_span]
-        span: Span,
-    },
-    #[suggestion(
-        infer_implicit_static_lifetime_suggestion,
-        style = "verbose",
-        code = " + '_",
-        applicability = "maybe-incorrect"
-    )]
-    Sugg {
-        #[primary_span]
-        span: Span,
-    },
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_mismatched_static_lifetime)]
-pub struct MismatchedStaticLifetime<'a> {
-    #[primary_span]
-    pub cause_span: Span,
-    #[subdiagnostic]
-    pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
-    #[subdiagnostic]
-    pub expl: Option<note_and_explain::RegionExplanation<'a>>,
-    #[subdiagnostic]
-    pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
-    #[subdiagnostic]
-    pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
-}
-
-#[derive(Diagnostic)]
-pub enum ExplicitLifetimeRequired<'a> {
-    #[diag(infer_explicit_lifetime_required_with_ident, code = E0621)]
-    WithIdent {
-        #[primary_span]
-        #[label]
-        span: Span,
-        simple_ident: Ident,
-        named: String,
-        #[suggestion(
-            infer_explicit_lifetime_required_sugg_with_ident,
-            code = "{new_ty}",
-            applicability = "unspecified"
-        )]
-        new_ty_span: Span,
-        #[skip_arg]
-        new_ty: Ty<'a>,
-    },
-    #[diag(infer_explicit_lifetime_required_with_param_type, code = E0621)]
-    WithParamType {
-        #[primary_span]
-        #[label]
-        span: Span,
-        named: String,
-        #[suggestion(
-            infer_explicit_lifetime_required_sugg_with_param_type,
-            code = "{new_ty}",
-            applicability = "unspecified"
-        )]
-        new_ty_span: Span,
-        #[skip_arg]
-        new_ty: Ty<'a>,
-    },
-}
-
-pub enum TyOrSig<'tcx> {
-    Ty(Highlighted<'tcx, Ty<'tcx>>),
-    ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
-}
-
-impl IntoDiagArg for TyOrSig<'_> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        match self {
-            TyOrSig::Ty(ty) => ty.into_diag_arg(),
-            TyOrSig::ClosureSig(sig) => sig.into_diag_arg(),
-        }
-    }
-}
-
-#[derive(Subdiagnostic)]
-pub enum ActualImplExplNotes<'tcx> {
-    #[note(infer_actual_impl_expl_expected_signature_two)]
-    ExpectedSignatureTwo {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-        lifetime_2: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_signature_any)]
-    ExpectedSignatureAny {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_signature_some)]
-    ExpectedSignatureSome {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_signature_nothing)]
-    ExpectedSignatureNothing {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-    },
-    #[note(infer_actual_impl_expl_expected_passive_two)]
-    ExpectedPassiveTwo {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-        lifetime_2: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_passive_any)]
-    ExpectedPassiveAny {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_passive_some)]
-    ExpectedPassiveSome {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_passive_nothing)]
-    ExpectedPassiveNothing {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-    },
-    #[note(infer_actual_impl_expl_expected_other_two)]
-    ExpectedOtherTwo {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-        lifetime_2: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_other_any)]
-    ExpectedOtherAny {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_other_some)]
-    ExpectedOtherSome {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-    },
-    #[note(infer_actual_impl_expl_expected_other_nothing)]
-    ExpectedOtherNothing {
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-    },
-    #[note(infer_actual_impl_expl_but_actually_implements_trait)]
-    ButActuallyImplementsTrait {
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        has_lifetime: bool,
-        lifetime: usize,
-    },
-    #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)]
-    ButActuallyImplementedForTy {
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        has_lifetime: bool,
-        lifetime: usize,
-        ty: String,
-    },
-    #[note(infer_actual_impl_expl_but_actually_ty_implements)]
-    ButActuallyTyImplements {
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        has_lifetime: bool,
-        lifetime: usize,
-        ty: String,
-    },
-}
-
-pub enum ActualImplExpectedKind {
-    Signature,
-    Passive,
-    Other,
-}
-
-pub enum ActualImplExpectedLifetimeKind {
-    Two,
-    Any,
-    Some,
-    Nothing,
-}
-
-impl<'tcx> ActualImplExplNotes<'tcx> {
-    pub fn new_expected(
-        kind: ActualImplExpectedKind,
-        lt_kind: ActualImplExpectedLifetimeKind,
-        leading_ellipsis: bool,
-        ty_or_sig: TyOrSig<'tcx>,
-        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-        lifetime_1: usize,
-        lifetime_2: usize,
-    ) -> Self {
-        match (kind, lt_kind) {
-            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
-                Self::ExpectedSignatureTwo {
-                    leading_ellipsis,
-                    ty_or_sig,
-                    trait_path,
-                    lifetime_1,
-                    lifetime_2,
-                }
-            }
-            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
-                Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
-            }
-            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
-                Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
-            }
-            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
-                Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
-            }
-            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
-                Self::ExpectedPassiveTwo {
-                    leading_ellipsis,
-                    ty_or_sig,
-                    trait_path,
-                    lifetime_1,
-                    lifetime_2,
-                }
-            }
-            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
-                Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
-            }
-            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
-                Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
-            }
-            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
-                Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
-            }
-            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
-                Self::ExpectedOtherTwo {
-                    leading_ellipsis,
-                    ty_or_sig,
-                    trait_path,
-                    lifetime_1,
-                    lifetime_2,
-                }
-            }
-            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
-                Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
-            }
-            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
-                Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
-            }
-            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
-                Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
-            }
-        }
-    }
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_trait_placeholder_mismatch)]
-pub struct TraitPlaceholderMismatch<'tcx> {
-    #[primary_span]
-    pub span: Span,
-    #[label(infer_label_satisfy)]
-    pub satisfy_span: Option<Span>,
-    #[label(infer_label_where)]
-    pub where_span: Option<Span>,
-    #[label(infer_label_dup)]
-    pub dup_span: Option<Span>,
-    pub def_id: String,
-    pub trait_def_id: String,
-
-    #[subdiagnostic]
-    pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
-}
-
-pub struct ConsiderBorrowingParamHelp {
-    pub spans: Vec<Span>,
-}
-
-impl Subdiagnostic for ConsiderBorrowingParamHelp {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        f: &F,
-    ) {
-        let mut type_param_span: MultiSpan = self.spans.clone().into();
-        for &span in &self.spans {
-            // Seems like we can't call f() here as Into<DiagMessage> is required
-            type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing);
-        }
-        let msg = f(diag, fluent::infer_tid_param_help.into());
-        diag.span_help(type_param_span, msg);
-    }
-}
-
-#[derive(Subdiagnostic)]
-#[help(infer_tid_rel_help)]
-pub struct RelationshipHelp;
-
-#[derive(Diagnostic)]
-#[diag(infer_trait_impl_diff)]
-pub struct TraitImplDiff {
-    #[primary_span]
-    #[label(infer_found)]
-    pub sp: Span,
-    #[label(infer_expected)]
-    pub trait_sp: Span,
-    #[note(infer_expected_found)]
-    pub note: (),
-    #[subdiagnostic]
-    pub param_help: ConsiderBorrowingParamHelp,
-    #[subdiagnostic]
-    // Seems like subdiagnostics are always pushed to the end, so this one
-    // also has to be a subdiagnostic to maintain order.
-    pub rel_help: Option<RelationshipHelp>,
-    pub expected: String,
-    pub found: String,
-}
-
-pub struct DynTraitConstraintSuggestion {
-    pub span: Span,
-    pub ident: Ident,
-}
-
-impl Subdiagnostic for DynTraitConstraintSuggestion {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        f: &F,
-    ) {
-        let mut multi_span: MultiSpan = vec![self.span].into();
-        multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
-        multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement);
-        let msg = f(diag, fluent::infer_dtcs_has_req_note.into());
-        diag.span_note(multi_span, msg);
-        let msg = f(diag, fluent::infer_dtcs_suggestion.into());
-        diag.span_suggestion_verbose(
-            self.span.shrink_to_hi(),
-            msg,
-            " + '_",
-            Applicability::MaybeIncorrect,
-        );
-    }
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_but_calling_introduces, code = E0772)]
-pub struct ButCallingIntroduces {
-    #[label(infer_label1)]
-    pub param_ty_span: Span,
-    #[primary_span]
-    #[label(infer_label2)]
-    pub cause_span: Span,
-
-    pub has_param_name: bool,
-    pub param_name: String,
-    pub has_lifetime: bool,
-    pub lifetime: String,
-    pub assoc_item: Symbol,
-    pub has_impl_path: bool,
-    pub impl_path: String,
-}
-
-pub struct ReqIntroducedLocations {
-    pub span: MultiSpan,
-    pub spans: Vec<Span>,
-    pub fn_decl_span: Span,
-    pub cause_span: Span,
-    pub add_label: bool,
-}
-
-impl Subdiagnostic for ReqIntroducedLocations {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        mut self,
-        diag: &mut Diag<'_, G>,
-        f: &F,
-    ) {
-        for sp in self.spans {
-            self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
-        }
-
-        if self.add_label {
-            self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by);
-        }
-        self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of);
-        let msg = f(diag, fluent::infer_ril_static_introduced_by.into());
-        diag.span_note(self.span, msg);
-    }
-}
-
-pub struct MoreTargeted {
-    pub ident: Symbol,
-}
-
-impl Subdiagnostic for MoreTargeted {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        _f: &F,
-    ) {
-        diag.code(E0772);
-        diag.primary_message(fluent::infer_more_targeted);
-        diag.arg("ident", self.ident);
-    }
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_but_needs_to_satisfy, code = E0759)]
-pub struct ButNeedsToSatisfy {
-    #[primary_span]
-    pub sp: Span,
-    #[label(infer_influencer)]
-    pub influencer_point: Span,
-    #[label(infer_used_here)]
-    pub spans: Vec<Span>,
-    #[label(infer_require)]
-    pub require_span_as_label: Option<Span>,
-    #[note(infer_require)]
-    pub require_span_as_note: Option<Span>,
-    #[note(infer_introduced_by_bound)]
-    pub bound: Option<Span>,
-
-    #[subdiagnostic]
-    pub req_introduces_loc: Option<ReqIntroducedLocations>,
-
-    pub has_param_name: bool,
-    pub param_name: String,
-    pub spans_empty: bool,
-    pub has_lifetime: bool,
-    pub lifetime: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_outlives_content, code = E0312)]
-pub struct OutlivesContent<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_outlives_bound, code = E0476)]
-pub struct OutlivesBound<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_fulfill_req_lifetime, code = E0477)]
-pub struct FulfillReqLifetime<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub ty: Ty<'a>,
-    #[subdiagnostic]
-    pub note: Option<note_and_explain::RegionExplanation<'a>>,
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_lf_bound_not_satisfied, code = E0478)]
-pub struct LfBoundNotSatisfied<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_ref_longer_than_data, code = E0491)]
-pub struct RefLongerThanData<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub ty: Ty<'a>,
-    #[subdiagnostic]
-    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
-}
-
-#[derive(Subdiagnostic)]
-pub enum WhereClauseSuggestions {
-    #[suggestion(
-        infer_where_remove,
-        code = "",
-        applicability = "machine-applicable",
-        style = "verbose"
-    )]
-    Remove {
-        #[primary_span]
-        span: Span,
-    },
-    #[suggestion(
-        infer_where_copy_predicates,
-        code = "{space}where {trait_predicates}",
-        applicability = "machine-applicable",
-        style = "verbose"
-    )]
-    CopyPredicates {
-        #[primary_span]
-        span: Span,
-        space: &'static str,
-        trait_predicates: String,
-    },
-}
-
-#[derive(Subdiagnostic)]
-pub enum SuggestRemoveSemiOrReturnBinding {
-    #[multipart_suggestion(infer_srs_remove_and_box, applicability = "machine-applicable")]
-    RemoveAndBox {
-        #[suggestion_part(code = "Box::new(")]
-        first_lo: Span,
-        #[suggestion_part(code = ")")]
-        first_hi: Span,
-        #[suggestion_part(code = "Box::new(")]
-        second_lo: Span,
-        #[suggestion_part(code = ")")]
-        second_hi: Span,
-        #[suggestion_part(code = "")]
-        sp: Span,
-    },
-    #[suggestion(
-        infer_srs_remove,
-        style = "short",
-        code = "",
-        applicability = "machine-applicable"
-    )]
-    Remove {
-        #[primary_span]
-        sp: Span,
-    },
-    #[suggestion(
-        infer_srs_add,
-        style = "verbose",
-        code = "{code}",
-        applicability = "maybe-incorrect"
-    )]
-    Add {
-        #[primary_span]
-        sp: Span,
-        code: String,
-        ident: Ident,
-    },
-    #[note(infer_srs_add_one)]
-    AddOne {
-        #[primary_span]
-        spans: MultiSpan,
-    },
-}
-
-#[derive(Subdiagnostic)]
-pub enum ConsiderAddingAwait {
-    #[help(infer_await_both_futures)]
-    BothFuturesHelp,
-    #[multipart_suggestion(infer_await_both_futures, applicability = "maybe-incorrect")]
-    BothFuturesSugg {
-        #[suggestion_part(code = ".await")]
-        first: Span,
-        #[suggestion_part(code = ".await")]
-        second: Span,
-    },
-    #[suggestion(
-        infer_await_future,
-        code = ".await",
-        style = "verbose",
-        applicability = "maybe-incorrect"
-    )]
-    FutureSugg {
-        #[primary_span]
-        span: Span,
-    },
-    #[note(infer_await_note)]
-    FutureSuggNote {
-        #[primary_span]
-        span: Span,
-    },
-    #[multipart_suggestion(
-        infer_await_future,
-        style = "verbose",
-        applicability = "maybe-incorrect"
-    )]
-    FutureSuggMultiple {
-        #[suggestion_part(code = ".await")]
-        spans: Vec<Span>,
-    },
-}
-
-#[derive(Diagnostic)]
-pub enum PlaceholderRelationLfNotSatisfied {
-    #[diag(infer_lf_bound_not_satisfied)]
-    HasBoth {
-        #[primary_span]
-        span: Span,
-        #[note(infer_prlf_defined_with_sub)]
-        sub_span: Span,
-        #[note(infer_prlf_must_outlive_with_sup)]
-        sup_span: Span,
-        sub_symbol: Symbol,
-        sup_symbol: Symbol,
-        #[note(infer_prlf_known_limitation)]
-        note: (),
-    },
-    #[diag(infer_lf_bound_not_satisfied)]
-    HasSub {
-        #[primary_span]
-        span: Span,
-        #[note(infer_prlf_defined_with_sub)]
-        sub_span: Span,
-        #[note(infer_prlf_must_outlive_without_sup)]
-        sup_span: Span,
-        sub_symbol: Symbol,
-        #[note(infer_prlf_known_limitation)]
-        note: (),
-    },
-    #[diag(infer_lf_bound_not_satisfied)]
-    HasSup {
-        #[primary_span]
-        span: Span,
-        #[note(infer_prlf_defined_without_sub)]
-        sub_span: Span,
-        #[note(infer_prlf_must_outlive_with_sup)]
-        sup_span: Span,
-        sup_symbol: Symbol,
-        #[note(infer_prlf_known_limitation)]
-        note: (),
-    },
-    #[diag(infer_lf_bound_not_satisfied)]
-    HasNone {
-        #[primary_span]
-        span: Span,
-        #[note(infer_prlf_defined_without_sub)]
-        sub_span: Span,
-        #[note(infer_prlf_must_outlive_without_sup)]
-        sup_span: Span,
-        #[note(infer_prlf_known_limitation)]
-        note: (),
-    },
-    #[diag(infer_lf_bound_not_satisfied)]
-    OnlyPrimarySpan {
-        #[primary_span]
-        span: Span,
-        #[note(infer_prlf_known_limitation)]
-        note: (),
-    },
-}
-
-#[derive(Diagnostic)]
-#[diag(infer_opaque_captures_lifetime, code = E0700)]
-pub struct OpaqueCapturesLifetime<'tcx> {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub opaque_ty_span: Span,
-    pub opaque_ty: Ty<'tcx>,
-}
-
-#[derive(Subdiagnostic)]
-pub enum FunctionPointerSuggestion<'a> {
-    #[suggestion(
-        infer_fps_use_ref,
-        code = "&{fn_name}",
-        style = "verbose",
-        applicability = "maybe-incorrect"
-    )]
-    UseRef {
-        #[primary_span]
-        span: Span,
-        #[skip_arg]
-        fn_name: String,
-    },
-    #[suggestion(
-        infer_fps_remove_ref,
-        code = "{fn_name}",
-        style = "verbose",
-        applicability = "maybe-incorrect"
-    )]
-    RemoveRef {
-        #[primary_span]
-        span: Span,
-        #[skip_arg]
-        fn_name: String,
-    },
-    #[suggestion(
-        infer_fps_cast,
-        code = "&({fn_name} as {sig})",
-        style = "verbose",
-        applicability = "maybe-incorrect"
-    )]
-    CastRef {
-        #[primary_span]
-        span: Span,
-        #[skip_arg]
-        fn_name: String,
-        #[skip_arg]
-        sig: Binder<'a, FnSig<'a>>,
-    },
-    #[suggestion(
-        infer_fps_cast,
-        code = "{fn_name} as {sig}",
-        style = "verbose",
-        applicability = "maybe-incorrect"
-    )]
-    Cast {
-        #[primary_span]
-        span: Span,
-        #[skip_arg]
-        fn_name: String,
-        #[skip_arg]
-        sig: Binder<'a, FnSig<'a>>,
-    },
-    #[suggestion(
-        infer_fps_cast_both,
-        code = "{fn_name} as {found_sig}",
-        style = "hidden",
-        applicability = "maybe-incorrect"
-    )]
-    CastBoth {
-        #[primary_span]
-        span: Span,
-        #[skip_arg]
-        fn_name: String,
-        #[skip_arg]
-        found_sig: Binder<'a, FnSig<'a>>,
-        expected_sig: Binder<'a, FnSig<'a>>,
-    },
-    #[suggestion(
-        infer_fps_cast_both,
-        code = "&({fn_name} as {found_sig})",
-        style = "hidden",
-        applicability = "maybe-incorrect"
-    )]
-    CastBothRef {
-        #[primary_span]
-        span: Span,
-        #[skip_arg]
-        fn_name: String,
-        #[skip_arg]
-        found_sig: Binder<'a, FnSig<'a>>,
-        expected_sig: Binder<'a, FnSig<'a>>,
-    },
-}
-
-#[derive(Subdiagnostic)]
-#[note(infer_fps_items_are_distinct)]
-pub struct FnItemsAreDistinct;
-
-#[derive(Subdiagnostic)]
-#[note(infer_fn_uniq_types)]
-pub struct FnUniqTypes;
-
-#[derive(Subdiagnostic)]
-#[help(infer_fn_consider_casting)]
-pub struct FnConsiderCasting {
-    pub casting: String,
-}
-
-#[derive(Subdiagnostic)]
-pub enum SuggestAccessingField<'a> {
-    #[suggestion(
-        infer_suggest_accessing_field,
-        code = "{snippet}.{name}",
-        applicability = "maybe-incorrect"
-    )]
-    Safe {
-        #[primary_span]
-        span: Span,
-        snippet: String,
-        name: Symbol,
-        ty: Ty<'a>,
-    },
-    #[suggestion(
-        infer_suggest_accessing_field,
-        code = "unsafe {{ {snippet}.{name} }}",
-        applicability = "maybe-incorrect"
-    )]
-    Unsafe {
-        #[primary_span]
-        span: Span,
-        snippet: String,
-        name: Symbol,
-        ty: Ty<'a>,
-    },
-}
-
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(infer_stp_wrap_one, applicability = "maybe-incorrect")]
-pub struct SuggestTuplePatternOne {
-    pub variant: String,
-    #[suggestion_part(code = "{variant}(")]
-    pub span_low: Span,
-    #[suggestion_part(code = ")")]
-    pub span_high: Span,
-}
-
-pub struct SuggestTuplePatternMany {
-    pub path: String,
-    pub cause_span: Span,
-    pub compatible_variants: Vec<String>,
-}
-
-impl Subdiagnostic for SuggestTuplePatternMany {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        f: &F,
-    ) {
-        diag.arg("path", self.path);
-        let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());
-        diag.multipart_suggestions(
-            message,
-            self.compatible_variants.into_iter().map(|variant| {
-                vec![
-                    (self.cause_span.shrink_to_lo(), format!("{variant}(")),
-                    (self.cause_span.shrink_to_hi(), ")".to_string()),
-                ]
-            }),
-            rustc_errors::Applicability::MaybeIncorrect,
-        );
-    }
-}
-
-#[derive(Subdiagnostic)]
-pub enum TypeErrorAdditionalDiags {
-    #[suggestion(
-        infer_meant_byte_literal,
-        code = "b'{code}'",
-        applicability = "machine-applicable"
-    )]
-    MeantByteLiteral {
-        #[primary_span]
-        span: Span,
-        code: String,
-    },
-    #[suggestion(
-        infer_meant_char_literal,
-        code = "'{code}'",
-        applicability = "machine-applicable"
-    )]
-    MeantCharLiteral {
-        #[primary_span]
-        span: Span,
-        code: String,
-    },
-    #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")]
-    MeantStrLiteral {
-        #[suggestion_part(code = "\"")]
-        start: Span,
-        #[suggestion_part(code = "\"")]
-        end: Span,
-    },
-    #[suggestion(
-        infer_consider_specifying_length,
-        code = "{length}",
-        applicability = "maybe-incorrect"
-    )]
-    ConsiderSpecifyingLength {
-        #[primary_span]
-        span: Span,
-        length: u64,
-    },
-    #[note(infer_try_cannot_convert)]
-    TryCannotConvert { found: String, expected: String },
-    #[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")]
-    TupleOnlyComma {
-        #[primary_span]
-        span: Span,
-    },
-    #[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")]
-    TupleAlsoParentheses {
-        #[suggestion_part(code = "(")]
-        span_low: Span,
-        #[suggestion_part(code = ",)")]
-        span_high: Span,
-    },
-    #[suggestion(
-        infer_suggest_add_let_for_letchains,
-        style = "verbose",
-        applicability = "machine-applicable",
-        code = "let "
-    )]
-    AddLetForLetChains {
-        #[primary_span]
-        span: Span,
-    },
-}
-
-#[derive(Diagnostic)]
-pub enum ObligationCauseFailureCode {
-    #[diag(infer_oc_method_compat, code = E0308)]
-    MethodCompat {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_type_compat, code = E0308)]
-    TypeCompat {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_const_compat, code = E0308)]
-    ConstCompat {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_try_compat, code = E0308)]
-    TryCompat {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_match_compat, code = E0308)]
-    MatchCompat {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_if_else_different, code = E0308)]
-    IfElseDifferent {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_no_else, code = E0317)]
-    NoElse {
-        #[primary_span]
-        span: Span,
-    },
-    #[diag(infer_oc_no_diverge, code = E0308)]
-    NoDiverge {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_fn_main_correct_type, code = E0580)]
-    FnMainCorrectType {
-        #[primary_span]
-        span: Span,
-    },
-    #[diag(infer_oc_fn_start_correct_type, code = E0308)]
-    FnStartCorrectType {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_fn_lang_correct_type, code = E0308)]
-    FnLangCorrectType {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-        lang_item_name: Symbol,
-    },
-    #[diag(infer_oc_intrinsic_correct_type, code = E0308)]
-    IntrinsicCorrectType {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_method_correct_type, code = E0308)]
-    MethodCorrectType {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_closure_selfref, code = E0644)]
-    ClosureSelfref {
-        #[primary_span]
-        span: Span,
-    },
-    #[diag(infer_oc_cant_coerce, code = E0308)]
-    CantCoerce {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-    #[diag(infer_oc_generic, code = E0308)]
-    Generic {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
-}
-
-#[derive(Subdiagnostic)]
-pub enum AddPreciseCapturing {
-    #[suggestion(
-        infer_precise_capturing_new,
-        style = "verbose",
-        code = " + use<{concatenated_bounds}>",
-        applicability = "machine-applicable"
-    )]
-    New {
-        #[primary_span]
-        span: Span,
-        new_lifetime: Symbol,
-        concatenated_bounds: String,
-    },
-    #[suggestion(
-        infer_precise_capturing_existing,
-        style = "verbose",
-        code = "{pre}{new_lifetime}{post}",
-        applicability = "machine-applicable"
-    )]
-    Existing {
-        #[primary_span]
-        span: Span,
-        new_lifetime: Symbol,
-        pre: &'static str,
-        post: &'static str,
-    },
-}
-
-pub struct AddPreciseCapturingAndParams {
-    pub suggs: Vec<(Span, String)>,
-    pub new_lifetime: Symbol,
-    pub apit_spans: Vec<Span>,
-}
-
-impl Subdiagnostic for AddPreciseCapturingAndParams {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        _f: &F,
-    ) {
-        diag.arg("new_lifetime", self.new_lifetime);
-        diag.multipart_suggestion_verbose(
-            fluent::infer_precise_capturing_new_but_apit,
-            self.suggs,
-            Applicability::MaybeIncorrect,
-        );
-        diag.span_note(self.apit_spans, fluent::infer_warn_removing_apit_params);
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index c9073d8c23e..7fc4e36d752 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -11,7 +11,6 @@ pub use BoundRegionConversionTime::*;
 pub use RegionVariableOrigin::*;
 pub use SubregionOrigin::*;
 
-use crate::error_reporting::infer::TypeErrCtxt;
 use crate::infer::relate::RelateResult;
 use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
 use free_regions::RegionRelations;
@@ -24,7 +23,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
 use rustc_data_structures::unify as ut;
-use rustc_errors::{Diag, ErrorGuaranteed};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::extension;
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
@@ -65,8 +65,6 @@ pub mod relate;
 pub mod resolve;
 pub(crate) mod snapshot;
 pub mod type_variable;
-// FIXME(error_reporting): Where should we put this?
-pub mod need_type_info;
 
 #[must_use]
 #[derive(Debug)]
@@ -698,36 +696,24 @@ impl<'tcx> InferCtxt<'tcx> {
         self.next_trait_solver
     }
 
-    /// Creates a `TypeErrCtxt` for emitting various inference errors.
-    /// During typeck, use `FnCtxt::err_ctxt` instead.
-    pub 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),
-            autoderef_steps: Box::new(|ty| {
-                debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
-                vec![(ty, vec![])]
-            }),
-        }
-    }
-
     pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
         t.fold_with(&mut self.freshener())
     }
 
-    /// Returns the origin of the type variable identified by `vid`, or `None`
-    /// if this is not a type variable.
+    /// Returns the origin of the type variable identified by `vid`.
     ///
-    /// No attempt is made to resolve `ty`.
-    pub fn type_var_origin(&self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
-        match *ty.kind() {
-            ty::Infer(ty::TyVar(vid)) => {
-                Some(self.inner.borrow_mut().type_variables().var_origin(vid))
-            }
-            _ => None,
+    /// No attempt is made to resolve `vid` to its root variable.
+    pub fn type_var_origin(&self, vid: TyVid) -> TypeVariableOrigin {
+        self.inner.borrow_mut().type_variables().var_origin(vid)
+    }
+
+    /// Returns the origin of the const variable identified by `vid`
+    // FIXME: We should store origins separately from the unification table
+    // so this doesn't need to be optional.
+    pub fn const_var_origin(&self, vid: ConstVid) -> Option<ConstVariableOrigin> {
+        match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
+            ConstVariableValue::Known { .. } => None,
+            ConstVariableValue::Unknown { origin, .. } => Some(origin),
         }
     }
 
@@ -1589,60 +1575,6 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    // [Note-Type-error-reporting]
-    // An invariant is that anytime the expected or actual type is Error (the special
-    // error type, meaning that an error occurred when typechecking this expression),
-    // this is a derived error. The error cascaded from another error (that was already
-    // reported), so it's not useful to display it to the user.
-    // The following methods implement this logic.
-    // They check if either the actual or expected type is Error, and don't print the error
-    // in this case. The typechecker should only ever report type errors involving mismatched
-    // types using one of these methods, and should not call span_err directly for such
-    // errors.
-    pub fn type_error_struct_with_diag<M>(
-        &self,
-        sp: Span,
-        mk_diag: M,
-        actual_ty: Ty<'tcx>,
-    ) -> Diag<'a>
-    where
-        M: FnOnce(String) -> Diag<'a>,
-    {
-        let actual_ty = self.resolve_vars_if_possible(actual_ty);
-        debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
-
-        let mut err = mk_diag(self.ty_to_string(actual_ty));
-
-        // Don't report an error if actual type is `Error`.
-        if actual_ty.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    }
-
-    pub fn report_mismatched_types(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        expected: Ty<'tcx>,
-        actual: Ty<'tcx>,
-        err: TypeError<'tcx>,
-    ) -> Diag<'a> {
-        self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
-    }
-
-    pub fn report_mismatched_consts(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        expected: ty::Const<'tcx>,
-        actual: ty::Const<'tcx>,
-        err: TypeError<'tcx>,
-    ) -> Diag<'a> {
-        self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
-    }
-}
-
 /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
 /// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
 #[derive(Copy, Clone, Debug)]
@@ -1888,3 +1820,32 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>(
 
     args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
 }
+
+impl<'tcx> InferCtxt<'tcx> {
+    /// Given a [`hir::Block`], get the span of its last expression or
+    /// statement, peeling off any inner blocks.
+    pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
+        let block = block.innermost_block();
+        if let Some(expr) = &block.expr {
+            expr.span
+        } else if let Some(stmt) = block.stmts.last() {
+            // possibly incorrect trailing `;` in the else arm
+            stmt.span
+        } else {
+            // empty block; point at its entirety
+            block.span
+        }
+    }
+
+    /// Given a [`hir::HirId`] for a block, get the span of its last expression
+    /// or statement, peeling off any inner blocks.
+    pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
+        match self.tcx.hir_node(hir_id) {
+            hir::Node::Block(blk) => self.find_block_span(blk),
+            // The parser was in a weird state if either of these happen, but
+            // it's better not to panic.
+            hir::Node::Expr(e) => e.span,
+            _ => rustc_span::DUMMY_SP,
+        }
+    }
+}
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 02ebf933f53..b65ac859667 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -34,7 +34,6 @@
 #[macro_use]
 extern crate tracing;
 
-pub mod error_reporting;
 mod errors;
 pub mod infer;
 pub mod traits;
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
deleted file mode 100644
index 7730fe29e09..00000000000
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ /dev/null
@@ -1,204 +0,0 @@
-use super::ObjectSafetyViolation;
-
-use crate::infer::InferCtxt;
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Span;
-use std::fmt;
-use std::iter;
-
-impl<'tcx> InferCtxt<'tcx> {
-    pub fn report_extra_impl_obligation<'a>(
-        &'a self,
-        error_span: Span,
-        impl_item_def_id: LocalDefId,
-        trait_item_def_id: DefId,
-        requirement: &dyn fmt::Display,
-    ) -> Diag<'a> {
-        let mut err = struct_span_code_err!(
-            self.dcx(),
-            error_span,
-            E0276,
-            "impl has stricter requirements than trait"
-        );
-
-        if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
-            if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) {
-                let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
-                err.span_label(span, format!("definition of `{item_name}` from trait"));
-            }
-        }
-
-        err.span_label(error_span, format!("impl has extra requirement {requirement}"));
-
-        err
-    }
-}
-
-pub fn report_object_safety_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    span: Span,
-    hir_id: Option<hir::HirId>,
-    trait_def_id: DefId,
-    violations: &[ObjectSafetyViolation],
-) -> Diag<'tcx> {
-    let trait_str = tcx.def_path_str(trait_def_id);
-    let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
-        hir::Node::Item(item) => Some(item.ident.span),
-        _ => None,
-    });
-    let mut err = struct_span_code_err!(
-        tcx.dcx(),
-        span,
-        E0038,
-        "the trait `{}` cannot be made into an object",
-        trait_str
-    );
-    err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
-
-    if let Some(hir_id) = hir_id
-        && let hir::Node::Ty(ty) = tcx.hir_node(hir_id)
-        && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
-    {
-        let mut hir_id = hir_id;
-        while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
-            hir_id = ty.hir_id;
-        }
-        if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
-            // Do not suggest `impl Trait` when dealing with things like super-traits.
-            err.span_suggestion_verbose(
-                ty.span.until(trait_ref.span),
-                "consider using an opaque type instead",
-                "impl ",
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
-    let mut reported_violations = FxIndexSet::default();
-    let mut multi_span = vec![];
-    let mut messages = vec![];
-    for violation in violations {
-        if let ObjectSafetyViolation::SizedSelf(sp) = &violation
-            && !sp.is_empty()
-        {
-            // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
-            // with a `Span`.
-            reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
-        }
-        if reported_violations.insert(violation.clone()) {
-            let spans = violation.spans();
-            let msg = if trait_span.is_none() || spans.is_empty() {
-                format!("the trait cannot be made into an object because {}", violation.error_msg())
-            } else {
-                format!("...because {}", violation.error_msg())
-            };
-            if spans.is_empty() {
-                err.note(msg);
-            } else {
-                for span in spans {
-                    multi_span.push(span);
-                    messages.push(msg.clone());
-                }
-            }
-        }
-    }
-    let has_multi_span = !multi_span.is_empty();
-    let mut note_span = MultiSpan::from_spans(multi_span.clone());
-    if let (Some(trait_span), true) = (trait_span, has_multi_span) {
-        note_span.push_span_label(trait_span, "this trait cannot be made into an object...");
-    }
-    for (span, msg) in iter::zip(multi_span, messages) {
-        note_span.push_span_label(span, msg);
-    }
-    err.span_note(
-        note_span,
-        "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \
-         to be resolvable dynamically; for more information visit \
-         <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
-    );
-
-    // Only provide the help if its a local trait, otherwise it's not actionable.
-    if trait_span.is_some() {
-        let mut reported_violations: Vec<_> = reported_violations.into_iter().collect();
-        reported_violations.sort();
-
-        let mut potential_solutions: Vec<_> =
-            reported_violations.into_iter().map(|violation| violation.solution()).collect();
-        potential_solutions.sort();
-        // Allows us to skip suggesting that the same item should be moved to another trait multiple times.
-        potential_solutions.dedup();
-        for solution in potential_solutions {
-            solution.add_to(&mut err);
-        }
-    }
-
-    let impls_of = tcx.trait_impls_of(trait_def_id);
-    let impls = if impls_of.blanket_impls().is_empty() {
-        impls_of
-            .non_blanket_impls()
-            .values()
-            .flatten()
-            .filter(|def_id| {
-                !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..))
-            })
-            .collect::<Vec<_>>()
-    } else {
-        vec![]
-    };
-    let externally_visible = if !impls.is_empty()
-        && let Some(def_id) = trait_def_id.as_local()
-        // We may be executing this during typeck, which would result in cycle
-        // if we used effective_visibilities query, which looks into opaque types
-        // (and therefore calls typeck).
-        && tcx.resolutions(()).effective_visibilities.is_exported(def_id)
-    {
-        true
-    } else {
-        false
-    };
-    match &impls[..] {
-        [] => {}
-        _ if impls.len() > 9 => {}
-        [only] if externally_visible => {
-            err.help(with_no_trimmed_paths!(format!(
-                "only type `{}` is seen to implement the trait in this crate, consider using it \
-                 directly instead",
-                tcx.type_of(*only).instantiate_identity(),
-            )));
-        }
-        [only] => {
-            err.help(with_no_trimmed_paths!(format!(
-                "only type `{}` implements the trait, consider using it directly instead",
-                tcx.type_of(*only).instantiate_identity(),
-            )));
-        }
-        impls => {
-            let mut types = impls
-                .iter()
-                .map(|t| {
-                    with_no_trimmed_paths!(format!("  {}", tcx.type_of(*t).instantiate_identity(),))
-                })
-                .collect::<Vec<_>>();
-            types.sort();
-            err.help(format!(
-                "the following types implement the trait, consider defining an enum where each \
-                 variant holds one of these types, implementing `{}` for this new enum and using \
-                 it instead:\n{}",
-                trait_str,
-                types.join("\n"),
-            ));
-        }
-    }
-    if externally_visible {
-        err.note(format!(
-            "`{trait_str}` can be implemented in other crates; if you want to support your users \
-             passing their own types here, you can't refer to a specific type",
-        ));
-    }
-
-    err
-}
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 556b3bd063d..7bc3af374fc 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -3,7 +3,6 @@
 //! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
 
 mod engine;
-pub mod error_reporting;
 mod project;
 mod structural_impls;
 pub mod util;
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 290f91045c4..fc073233d97 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -322,6 +322,8 @@ fn register_builtins(store: &mut LintStore) {
         REFINING_IMPL_TRAIT_INTERNAL
     );
 
+    add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024);
+
     // Register renamed and removed lints.
     store.register_renamed("single_use_lifetime", "single_use_lifetimes");
     store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths");
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 04764b71b10..2f4e6a32308 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -37,7 +37,7 @@ declare_lint_pass! {
         DEPRECATED,
         DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
         DEPRECATED_IN_FUTURE,
-        DEPRECATED_SAFE,
+        DEPRECATED_SAFE_2024,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
         DUPLICATE_MACRO_ATTRIBUTES,
         ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
@@ -4812,8 +4812,8 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `deprecated_safe` lint detects unsafe functions being used as safe
-    /// functions.
+    /// The `deprecated_safe_2024` lint detects unsafe functions being used as
+    /// safe functions.
     ///
     /// ### Example
     ///
@@ -4832,8 +4832,8 @@ declare_lint! {
     ///
     /// Rust [editions] allow the language to evolve without breaking backward
     /// compatibility. This lint catches code that uses `unsafe` functions that
-    /// were declared as safe (non-`unsafe`) in earlier editions. If you switch
-    /// the compiler to a new edition without updating the code, then it
+    /// were declared as safe (non-`unsafe`) in editions prior to Rust 2024. If
+    /// you switch the compiler to Rust 2024 without updating the code, then it
     /// will fail to compile if you are using a function previously marked as
     /// safe.
     ///
@@ -4850,7 +4850,7 @@ declare_lint! {
     /// future.
     ///
     /// [editions]: https://doc.rust-lang.org/edition-guide/
-    pub DEPRECATED_SAFE,
+    pub DEPRECATED_SAFE_2024,
     Allow,
     "detects unsafe functions being used as safe functions",
     @future_incompatible = FutureIncompatibleInfo {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 0ba9b940eed..e5e430bc90d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -7,6 +7,7 @@ use crate::rmeta::*;
 use rustc_ast as ast;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::owned_slice::OwnedSlice;
 use rustc_data_structures::sync::{Lock, Lrc, OnceLock};
 use rustc_data_structures::unhash::UnhashMap;
@@ -83,12 +84,12 @@ pub(crate) struct CrateMetadata {
     /// Trait impl data.
     /// FIXME: Used only from queries and can use query cache,
     /// so pre-decoding can probably be avoided.
-    trait_impls: FxHashMap<(u32, DefIndex), LazyArray<(DefIndex, Option<SimplifiedType>)>>,
+    trait_impls: FxIndexMap<(u32, DefIndex), LazyArray<(DefIndex, Option<SimplifiedType>)>>,
     /// Inherent impls which do not follow the normal coherence rules.
     ///
     /// These can be introduced using either `#![rustc_coherence_is_core]`
     /// or `#[rustc_allow_incoherent_impl]`.
-    incoherent_impls: FxHashMap<SimplifiedType, LazyArray<DefIndex>>,
+    incoherent_impls: FxIndexMap<SimplifiedType, LazyArray<DefIndex>>,
     /// Proc macro descriptions for this crate, if it's a proc macro crate.
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 8596a0645e4..6f31c0fa520 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -2,7 +2,7 @@ use crate::errors::{FailCreateFileEncoder, FailWriteFile};
 use crate::rmeta::*;
 
 use rustc_ast::Attribute;
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::{Mmap, MmapMut};
 use rustc_data_structures::sync::{join, par_for_each_in, Lrc};
 use rustc_data_structures::temp_dir::MaybeTempDir;
@@ -13,7 +13,6 @@ use rustc_hir_pretty::id_to_string;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::metadata_symbol_name;
 use rustc_middle::mir::interpret;
-use rustc_middle::query::LocalCrate;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
@@ -1509,10 +1508,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
         }
 
-        let inherent_impls = tcx.with_stable_hashing_context(|hcx| {
-            tcx.crate_inherent_impls(()).unwrap().inherent_impls.to_sorted(&hcx, true)
-        });
-        for (def_id, impls) in inherent_impls {
+        for (def_id, impls) in &tcx.crate_inherent_impls(()).unwrap().inherent_impls {
             record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| {
                 assert!(def_id.is_local());
                 def_id.index
@@ -2002,8 +1998,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
-        let mut fx_hash_map: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> =
-            FxHashMap::default();
+        let mut trait_impls: FxIndexMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> =
+            FxIndexMap::default();
 
         for id in tcx.hir().items() {
             let DefKind::Impl { of_trait } = tcx.def_kind(id.owner_id) else {
@@ -2022,7 +2018,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     trait_ref.self_ty(),
                     TreatParams::AsCandidateKey,
                 );
-                fx_hash_map
+                trait_impls
                     .entry(trait_ref.def_id)
                     .or_default()
                     .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
@@ -2043,47 +2039,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
         }
 
-        let mut all_impls: Vec<_> = fx_hash_map.into_iter().collect();
-
-        // Bring everything into deterministic order for hashing
-        all_impls.sort_by_cached_key(|&(trait_def_id, _)| tcx.def_path_hash(trait_def_id));
-
-        let all_impls: Vec<_> = all_impls
+        let trait_impls: Vec<_> = trait_impls
             .into_iter()
-            .map(|(trait_def_id, mut impls)| {
-                // Bring everything into deterministic order for hashing
-                impls.sort_by_cached_key(|&(index, _)| {
-                    tcx.hir().def_path_hash(LocalDefId { local_def_index: index })
-                });
-
-                TraitImpls {
-                    trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
-                    impls: self.lazy_array(&impls),
-                }
+            .map(|(trait_def_id, impls)| TraitImpls {
+                trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
+                impls: self.lazy_array(&impls),
             })
             .collect();
 
-        self.lazy_array(&all_impls)
+        self.lazy_array(&trait_impls)
     }
 
     #[instrument(level = "debug", skip(self))]
     fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
-        let all_impls = tcx.with_stable_hashing_context(|hcx| {
-            tcx.crate_inherent_impls(()).unwrap().incoherent_impls.to_sorted(&hcx, true)
-        });
 
-        let all_impls: Vec<_> = all_impls
-            .into_iter()
-            .map(|(&simp, impls)| {
-                let mut impls: Vec<_> =
-                    impls.into_iter().map(|def_id| def_id.local_def_index).collect();
-                impls.sort_by_cached_key(|&local_def_index| {
-                    tcx.hir().def_path_hash(LocalDefId { local_def_index })
-                });
-
-                IncoherentImpls { self_ty: simp, impls: self.lazy_array(impls) }
+        let all_impls: Vec<_> = tcx
+            .crate_inherent_impls(())
+            .unwrap()
+            .incoherent_impls
+            .iter()
+            .map(|(&simp, impls)| IncoherentImpls {
+                self_ty: simp,
+                impls: self.lazy_array(impls.iter().map(|def_id| def_id.local_def_index)),
             })
             .collect();
 
@@ -2327,32 +2306,6 @@ pub fn provide(providers: &mut Providers) {
                 span_bug!(tcx.def_span(def_id), "no traits in scope for a doc link")
             })
         },
-        traits: |tcx, LocalCrate| {
-            let mut traits = Vec::new();
-            for id in tcx.hir().items() {
-                if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
-                    traits.push(id.owner_id.to_def_id())
-                }
-            }
-
-            // Bring everything into deterministic order.
-            traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
-            tcx.arena.alloc_slice(&traits)
-        },
-        trait_impls_in_crate: |tcx, LocalCrate| {
-            let mut trait_impls = Vec::new();
-            for id in tcx.hir().items() {
-                if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. })
-                    && tcx.impl_trait_ref(id.owner_id).is_some()
-                {
-                    trait_impls.push(id.owner_id.to_def_id())
-                }
-            }
-
-            // Bring everything into deterministic order.
-            trait_impls.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
-            tcx.arena.alloc_slice(&trait_impls)
-        },
 
         ..*providers
     }
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index bf10a71dbae..75dc685a16a 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -103,6 +103,10 @@ declare_hooks! {
 
     /// Create a list-like THIR representation for debugging.
     hook thir_flat(key: LocalDefId) -> String;
+
+    /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
+    /// can just link to the upstream crate and therefore don't need a mono item.
+    hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
 }
 
 #[cold]
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index bdd1eb11a38..15febfa7d9c 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -12,15 +12,13 @@ use std::fmt;
 use std::io;
 use std::io::{Read, Write};
 use std::num::NonZero;
-use std::sync::atomic::{AtomicU32, Ordering};
 
-use smallvec::{smallvec, SmallVec};
 use tracing::{debug, trace};
 
 use rustc_ast::LitKind;
 use rustc_attr::InlineAttr;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::{HashMapExt, Lock};
+use rustc_data_structures::sync::Lock;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
@@ -159,14 +157,9 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
     }
 }
 
-// Used to avoid infinite recursion when decoding cyclic allocations.
-type DecodingSessionId = NonZero<u32>;
-
 #[derive(Clone)]
 enum State {
     Empty,
-    InProgressNonAlloc(SmallVec<[DecodingSessionId; 1]>),
-    InProgress(SmallVec<[DecodingSessionId; 1]>, AllocId),
     Done(AllocId),
 }
 
@@ -180,13 +173,7 @@ pub struct AllocDecodingState {
 impl AllocDecodingState {
     #[inline]
     pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
-        static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
-        let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
-
-        // Make sure this is never zero.
-        let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap();
-
-        AllocDecodingSession { state: self, session_id }
+        AllocDecodingSession { state: self }
     }
 
     pub fn new(data_offsets: Vec<u64>) -> Self {
@@ -200,7 +187,6 @@ impl AllocDecodingState {
 #[derive(Copy, Clone)]
 pub struct AllocDecodingSession<'s> {
     state: &'s AllocDecodingState,
-    session_id: DecodingSessionId,
 }
 
 impl<'s> AllocDecodingSession<'s> {
@@ -220,70 +206,35 @@ impl<'s> AllocDecodingSession<'s> {
             (alloc_kind, decoder.position())
         });
 
+        // We are going to hold this lock during the entire decoding of this allocation, which may
+        // require that we decode other allocations. This cannot deadlock for two reasons:
+        //
+        // At the time of writing, it is only possible to create an allocation that contains a pointer
+        // to itself using the const_allocate intrinsic (which is for testing only), and even attempting
+        // to evaluate such consts blows the stack. If we ever grow a mechanism for producing
+        // cyclic allocations, we will need a new strategy for decoding that doesn't bring back
+        // https://github.com/rust-lang/rust/issues/126741.
+        //
+        // It is also impossible to create two allocations (call them A and B) where A is a pointer to B, and B
+        // is a pointer to A, because attempting to evaluate either of those consts will produce a
+        // query cycle, failing compilation.
+        let mut entry = self.state.decoding_state[idx].lock();
         // Check the decoding state to see if it's already decoded or if we should
         // decode it here.
-        let alloc_id = {
-            let mut entry = self.state.decoding_state[idx].lock();
-
-            match *entry {
-                State::Done(alloc_id) => {
-                    return alloc_id;
-                }
-                ref mut entry @ State::Empty => {
-                    // We are allowed to decode.
-                    match alloc_kind {
-                        AllocDiscriminant::Alloc => {
-                            // If this is an allocation, we need to reserve an
-                            // `AllocId` so we can decode cyclic graphs.
-                            let alloc_id = decoder.interner().reserve_alloc_id();
-                            *entry = State::InProgress(smallvec![self.session_id], alloc_id);
-                            Some(alloc_id)
-                        }
-                        AllocDiscriminant::Fn
-                        | AllocDiscriminant::Static
-                        | AllocDiscriminant::VTable => {
-                            // Fns and statics cannot be cyclic, and their `AllocId`
-                            // is determined later by interning.
-                            *entry = State::InProgressNonAlloc(smallvec![self.session_id]);
-                            None
-                        }
-                    }
-                }
-                State::InProgressNonAlloc(ref mut sessions) => {
-                    if sessions.contains(&self.session_id) {
-                        bug!("this should be unreachable");
-                    } else {
-                        // Start decoding concurrently.
-                        sessions.push(self.session_id);
-                        None
-                    }
-                }
-                State::InProgress(ref mut sessions, alloc_id) => {
-                    if sessions.contains(&self.session_id) {
-                        // Don't recurse.
-                        return alloc_id;
-                    } else {
-                        // Start decoding concurrently.
-                        sessions.push(self.session_id);
-                        Some(alloc_id)
-                    }
-                }
-            }
-        };
+        if let State::Done(alloc_id) = *entry {
+            return alloc_id;
+        }
 
         // Now decode the actual data.
         let alloc_id = decoder.with_position(pos, |decoder| {
             match alloc_kind {
                 AllocDiscriminant::Alloc => {
+                    trace!("creating memory alloc ID");
                     let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
-                    // We already have a reserved `AllocId`.
-                    let alloc_id = alloc_id.unwrap();
-                    trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
-                    decoder.interner().set_alloc_id_same_memory(alloc_id, alloc);
-                    alloc_id
+                    trace!("decoded alloc {:?}", alloc);
+                    decoder.interner().reserve_and_set_memory_alloc(alloc)
                 }
                 AllocDiscriminant::Fn => {
-                    assert!(alloc_id.is_none());
                     trace!("creating fn alloc ID");
                     let instance = ty::Instance::decode(decoder);
                     trace!("decoded fn alloc instance: {:?}", instance);
@@ -291,35 +242,26 @@ impl<'s> AllocDecodingSession<'s> {
                     // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which
                     // is not possible in this context. That's why the allocation stores
                     // whether it is unique or not.
-                    let alloc_id =
-                        decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique);
-                    alloc_id
+                    decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique)
                 }
                 AllocDiscriminant::VTable => {
-                    assert!(alloc_id.is_none());
                     trace!("creating vtable alloc ID");
                     let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
                     let poly_trait_ref =
                         <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
                     trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
-                    let alloc_id =
-                        decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref);
-                    alloc_id
+                    decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref)
                 }
                 AllocDiscriminant::Static => {
-                    assert!(alloc_id.is_none());
                     trace!("creating extern static alloc ID");
                     let did = <DefId as Decodable<D>>::decode(decoder);
                     trace!("decoded static def-ID: {:?}", did);
-                    let alloc_id = decoder.interner().reserve_and_set_static_alloc(did);
-                    alloc_id
+                    decoder.interner().reserve_and_set_static_alloc(did)
                 }
             }
         });
 
-        self.state.decoding_state[idx].with_lock(|entry| {
-            *entry = State::Done(alloc_id);
-        });
+        *entry = State::Done(alloc_id);
 
         alloc_id
     }
@@ -563,12 +505,6 @@ impl<'tcx> TyCtxt<'tcx> {
             bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
         }
     }
-
-    /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
-    /// twice for the same `(AllocId, Allocation)` pair.
-    fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
-        self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
-    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index bd073cd891f..558590af7ec 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -40,7 +40,6 @@ use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
-use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
@@ -2083,6 +2082,8 @@ pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         trait_impls_of: trait_def::trait_impls_of_provider,
         incoherent_impls: trait_def::incoherent_impls_provider,
+        trait_impls_in_crate: trait_def::trait_impls_in_crate_provider,
+        traits: trait_def::traits_provider,
         const_param_default: consts::const_param_default,
         vtable_allocation: vtable::vtable_allocation_provider,
         ..*providers
@@ -2096,8 +2097,8 @@ pub fn provide(providers: &mut Providers) {
 /// (constructing this map requires touching the entire crate).
 #[derive(Clone, Debug, Default, HashStable)]
 pub struct CrateInherentImpls {
-    pub inherent_impls: LocalDefIdMap<Vec<DefId>>,
-    pub incoherent_impls: UnordMap<SimplifiedType, Vec<LocalDefId>>,
+    pub inherent_impls: FxIndexMap<LocalDefId, Vec<DefId>>,
+    pub incoherent_impls: FxIndexMap<SimplifiedType, Vec<LocalDefId>>,
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index da5860043c9..3bd9f6ad11b 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,16 +1,19 @@
-use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
-use crate::ty::{Ident, Ty, TyCtxt};
-use hir::def_id::LOCAL_CRATE;
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use std::iter;
 use tracing::debug;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_macros::{Decodable, Encodable, HashStable};
 
+use crate::query::LocalCrate;
+use crate::traits::specialization_graph;
+use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use crate::ty::{Ident, Ty, TyCtxt};
+
 /// A trait's definition with type information.
 #[derive(HashStable, Encodable, Decodable)]
 pub struct TraitDef {
@@ -274,3 +277,27 @@ pub(super) fn incoherent_impls_provider(
 
     Ok(tcx.arena.alloc_slice(&impls))
 }
+
+pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] {
+    let mut traits = Vec::new();
+    for id in tcx.hir().items() {
+        if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
+            traits.push(id.owner_id.to_def_id())
+        }
+    }
+
+    tcx.arena.alloc_slice(&traits)
+}
+
+pub(super) fn trait_impls_in_crate_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] {
+    let mut trait_impls = Vec::new();
+    for id in tcx.hir().items() {
+        if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. })
+            && tcx.impl_trait_ref(id.owner_id).is_some()
+        {
+            trait_impls.push(id.owner_id.to_def_id())
+        }
+    }
+
+    tcx.arena.alloc_slice(&trait_impls)
+}
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 7f4a2e73d33..95bc8b3d0cb 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1598,6 +1598,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 for subcandidate in candidate.subcandidates.iter_mut() {
                     expanded_candidates.push(subcandidate);
                 }
+                // Note that the subcandidates have been added to `expanded_candidates`,
+                // but `candidate` itself has not. If the last candidate has more match pairs,
+                // they are handled separately by `test_remaining_match_pairs_after_or`.
             } else {
                 // A candidate that doesn't start with an or-pattern has nothing to
                 // expand, so it is included in the post-expansion list as-is.
@@ -1613,19 +1616,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             expanded_candidates.as_mut_slice(),
         );
 
-        // Simplify subcandidates and process any leftover match pairs.
-        for candidate in candidates_to_expand {
+        // Postprocess subcandidates, and process any leftover match pairs.
+        // (Only the last candidate can possibly have more match pairs.)
+        debug_assert!({
+            let mut all_except_last = candidates_to_expand.iter().rev().skip(1);
+            all_except_last.all(|candidate| candidate.match_pairs.is_empty())
+        });
+        for candidate in candidates_to_expand.iter_mut() {
             if !candidate.subcandidates.is_empty() {
-                self.finalize_or_candidate(span, scrutinee_span, candidate);
+                self.merge_trivial_subcandidates(candidate);
+                self.remove_never_subcandidates(candidate);
             }
         }
+        if let Some(last_candidate) = candidates_to_expand.last_mut() {
+            self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate);
+        }
 
         remainder_start.and(remaining_candidates)
     }
 
     /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
-    /// subcandidate. Any candidate that has been expanded that way should be passed to
-    /// `finalize_or_candidate` after its subcandidates have been processed.
+    /// subcandidate. Any candidate that has been expanded this way should also be postprocessed
+    /// at the end of [`Self::expand_and_match_or_candidates`].
     fn create_or_subcandidates<'pat>(
         &mut self,
         candidate: &mut Candidate<'pat, 'tcx>,
@@ -1642,7 +1654,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
     }
 
-    /// Simplify subcandidates and process any leftover match pairs. The candidate should have been
+    /// Try to merge all of the subcandidates of the given candidate into one. This avoids
+    /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
     /// expanded with `create_or_subcandidates`.
     ///
     /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
@@ -1695,103 +1708,128 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///      |
     ///     ...
     /// ```
-    fn finalize_or_candidate(
-        &mut self,
-        span: Span,
-        scrutinee_span: Span,
-        candidate: &mut Candidate<'_, 'tcx>,
-    ) {
-        if candidate.subcandidates.is_empty() {
+    ///
+    /// Note that this takes place _after_ the subcandidates have participated
+    /// in match tree lowering.
+    fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
+        assert!(!candidate.subcandidates.is_empty());
+        if candidate.has_guard {
+            // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
             return;
         }
 
-        self.merge_trivial_subcandidates(candidate);
+        // FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
+        let can_merge = candidate.subcandidates.iter().all(|subcandidate| {
+            subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
+        });
+        if !can_merge {
+            return;
+        }
 
-        if !candidate.match_pairs.is_empty() {
-            let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span);
-            let source_info = self.source_info(or_span);
-            // If more match pairs remain, test them after each subcandidate.
-            // We could add them to the or-candidates before the call to `test_or_pattern` but this
-            // would make it impossible to detect simplifiable or-patterns. That would guarantee
-            // exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
-            let mut last_otherwise = None;
-            candidate.visit_leaves(|leaf_candidate| {
-                last_otherwise = leaf_candidate.otherwise_block;
-            });
-            let remaining_match_pairs = mem::take(&mut candidate.match_pairs);
-            candidate.visit_leaves(|leaf_candidate| {
-                assert!(leaf_candidate.match_pairs.is_empty());
-                leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
-                let or_start = leaf_candidate.pre_binding_block.unwrap();
-                let otherwise =
-                    self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]);
-                // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
-                // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
-                // directly to `last_otherwise`. If there is a guard,
-                // `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we
-                // can't skip `Q`.
-                let or_otherwise = if leaf_candidate.has_guard {
-                    leaf_candidate.otherwise_block.unwrap()
-                } else {
-                    last_otherwise.unwrap()
-                };
-                self.cfg.goto(otherwise, source_info, or_otherwise);
-            });
+        let mut last_otherwise = None;
+        let shared_pre_binding_block = self.cfg.start_new_block();
+        // This candidate is about to become a leaf, so unset `or_span`.
+        let or_span = candidate.or_span.take().unwrap();
+        let source_info = self.source_info(or_span);
+
+        if candidate.false_edge_start_block.is_none() {
+            candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block;
+        }
+
+        // Remove the (known-trivial) subcandidates from the candidate tree,
+        // so that they aren't visible after match tree lowering, and wire them
+        // all to join up at a single shared pre-binding block.
+        // (Note that the subcandidates have already had their part of the match
+        // tree lowered by this point, which is why we can add a goto to them.)
+        for subcandidate in mem::take(&mut candidate.subcandidates) {
+            let subcandidate_block = subcandidate.pre_binding_block.unwrap();
+            self.cfg.goto(subcandidate_block, source_info, shared_pre_binding_block);
+            last_otherwise = subcandidate.otherwise_block;
         }
+        candidate.pre_binding_block = Some(shared_pre_binding_block);
+        assert!(last_otherwise.is_some());
+        candidate.otherwise_block = last_otherwise;
     }
 
-    /// Try to merge all of the subcandidates of the given candidate into one. This avoids
-    /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
-    /// expanded with `create_or_subcandidates`.
-    fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
-        if candidate.subcandidates.is_empty() || candidate.has_guard {
-            // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
+    /// Never subcandidates may have a set of bindings inconsistent with their siblings,
+    /// which would break later code. So we filter them out. Note that we can't filter out
+    /// top-level candidates this way.
+    fn remove_never_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
+        if candidate.subcandidates.is_empty() {
             return;
         }
 
-        // FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
-        let can_merge = candidate.subcandidates.iter().all(|subcandidate| {
-            subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
-        });
-        if can_merge {
-            let mut last_otherwise = None;
-            let any_matches = self.cfg.start_new_block();
-            let or_span = candidate.or_span.take().unwrap();
-            let source_info = self.source_info(or_span);
-            if candidate.false_edge_start_block.is_none() {
-                candidate.false_edge_start_block =
-                    candidate.subcandidates[0].false_edge_start_block;
-            }
-            for subcandidate in mem::take(&mut candidate.subcandidates) {
-                let or_block = subcandidate.pre_binding_block.unwrap();
-                self.cfg.goto(or_block, source_info, any_matches);
-                last_otherwise = subcandidate.otherwise_block;
-            }
-            candidate.pre_binding_block = Some(any_matches);
-            assert!(last_otherwise.is_some());
-            candidate.otherwise_block = last_otherwise;
-        } else {
-            // Never subcandidates may have a set of bindings inconsistent with their siblings,
-            // which would break later code. So we filter them out. Note that we can't filter out
-            // top-level candidates this way.
-            candidate.subcandidates.retain_mut(|candidate| {
-                if candidate.extra_data.is_never {
-                    candidate.visit_leaves(|subcandidate| {
-                        let block = subcandidate.pre_binding_block.unwrap();
-                        // That block is already unreachable but needs a terminator to make the MIR well-formed.
-                        let source_info = self.source_info(subcandidate.extra_data.span);
-                        self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
-                    });
-                    false
-                } else {
-                    true
-                }
-            });
-            if candidate.subcandidates.is_empty() {
-                // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
-                candidate.pre_binding_block = Some(self.cfg.start_new_block());
+        candidate.subcandidates.retain_mut(|candidate| {
+            if candidate.extra_data.is_never {
+                candidate.visit_leaves(|subcandidate| {
+                    let block = subcandidate.pre_binding_block.unwrap();
+                    // That block is already unreachable but needs a terminator to make the MIR well-formed.
+                    let source_info = self.source_info(subcandidate.extra_data.span);
+                    self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
+                });
+                false
+            } else {
+                true
             }
+        });
+        if candidate.subcandidates.is_empty() {
+            // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
+            candidate.pre_binding_block = Some(self.cfg.start_new_block());
+        }
+    }
+
+    /// If more match pairs remain, test them after each subcandidate.
+    /// We could have added them to the or-candidates during or-pattern expansion, but that
+    /// would make it impossible to detect simplifiable or-patterns. That would guarantee
+    /// exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
+    fn test_remaining_match_pairs_after_or(
+        &mut self,
+        span: Span,
+        scrutinee_span: Span,
+        candidate: &mut Candidate<'_, 'tcx>,
+    ) {
+        if candidate.match_pairs.is_empty() {
+            return;
         }
+
+        let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span);
+        let source_info = self.source_info(or_span);
+        let mut last_otherwise = None;
+        candidate.visit_leaves(|leaf_candidate| {
+            last_otherwise = leaf_candidate.otherwise_block;
+        });
+
+        let remaining_match_pairs = mem::take(&mut candidate.match_pairs);
+        // We're testing match pairs that remained after an `Or`, so the remaining
+        // pairs should all be `Or` too, due to the sorting invariant.
+        debug_assert!(
+            remaining_match_pairs
+                .iter()
+                .all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
+        );
+
+        candidate.visit_leaves(|leaf_candidate| {
+            // At this point the leaf's own match pairs have all been lowered
+            // and removed, so `extend` and assignment are equivalent,
+            // but extending can also recycle any existing vector capacity.
+            assert!(leaf_candidate.match_pairs.is_empty());
+            leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
+
+            let or_start = leaf_candidate.pre_binding_block.unwrap();
+            let otherwise =
+                self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]);
+            // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
+            // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
+            // directly to `last_otherwise`. If there is a guard,
+            // `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we
+            // can't skip `Q`.
+            let or_otherwise = if leaf_candidate.has_guard {
+                leaf_candidate.otherwise_block.unwrap()
+            } else {
+                last_otherwise.unwrap()
+            };
+            self.cfg.goto(otherwise, source_info, or_otherwise);
+        });
     }
 
     /// Pick a test to run. Which test doesn't matter as long as it is guaranteed to fully match at
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index a65586ccdb7..bff4d6af4aa 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -10,7 +10,7 @@ use rustc_middle::thir::visit::Visitor;
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
-use rustc_session::lint::builtin::{DEPRECATED_SAFE, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
+use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::Symbol;
@@ -99,7 +99,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
             {
                 let sm = self.tcx.sess.source_map();
                 self.tcx.emit_node_span_lint(
-                    DEPRECATED_SAFE,
+                    DEPRECATED_SAFE_2024,
                     self.hir_context,
                     span,
                     CallToDeprecatedSafeFnRequiresUnsafe {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 70065b5a2c3..95799cec94b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -16,8 +16,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_pattern_analysis::errors::Uncovered;
 use rustc_pattern_analysis::rustc::{
-    Constructor, DeconstructedPat, MatchArm, RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport,
-    WitnessPat,
+    Constructor, DeconstructedPat, MatchArm, RevealedTy, RustcPatCtxt as PatCtxt, Usefulness,
+    UsefulnessReport, WitnessPat,
 };
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
@@ -998,27 +998,31 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     err.note(format!("the matched value is of type `{}`", scrut_ty));
 
     if !is_empty_match {
-        let mut non_exhaustive_tys = FxIndexSet::default();
+        let mut special_tys = FxIndexSet::default();
         // Look at the first witness.
-        collect_non_exhaustive_tys(cx, &witnesses[0], &mut non_exhaustive_tys);
+        collect_special_tys(cx, &witnesses[0], &mut special_tys);
 
-        for ty in non_exhaustive_tys {
+        for ty in special_tys {
             if ty.is_ptr_sized_integral() {
-                if ty == cx.tcx.types.usize {
+                if ty.inner() == cx.tcx.types.usize {
                     err.note(format!(
                         "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
                              exhaustively",
                     ));
-                } else if ty == cx.tcx.types.isize {
+                } else if ty.inner() == cx.tcx.types.isize {
                     err.note(format!(
                         "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
                              exhaustively",
                     ));
                 }
-            } else if ty == cx.tcx.types.str_ {
+            } else if ty.inner() == cx.tcx.types.str_ {
                 err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary");
-            } else if cx.is_foreign_non_exhaustive_enum(cx.reveal_opaque_ty(ty)) {
+            } else if cx.is_foreign_non_exhaustive_enum(ty) {
                 err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
+            } else if cx.is_uninhabited(ty.inner()) && cx.tcx.features().min_exhaustive_patterns {
+                // The type is uninhabited yet there is a witness: we must be in the `MaybeInvalid`
+                // case.
+                err.note(format!("`{ty}` is uninhabited but is not being matched by value, so a wildcard `_` is required"));
             }
         }
     }
@@ -1168,22 +1172,22 @@ fn joined_uncovered_patterns<'p, 'tcx>(
     }
 }
 
-fn collect_non_exhaustive_tys<'tcx>(
+/// Collect types that require specific explanations when they show up in witnesses.
+fn collect_special_tys<'tcx>(
     cx: &PatCtxt<'_, 'tcx>,
     pat: &WitnessPat<'_, 'tcx>,
-    non_exhaustive_tys: &mut FxIndexSet<Ty<'tcx>>,
+    special_tys: &mut FxIndexSet<RevealedTy<'tcx>>,
 ) {
-    if matches!(pat.ctor(), Constructor::NonExhaustive) {
-        non_exhaustive_tys.insert(pat.ty().inner());
+    if matches!(pat.ctor(), Constructor::NonExhaustive | Constructor::Never) {
+        special_tys.insert(*pat.ty());
     }
     if let Constructor::IntRange(range) = pat.ctor() {
         if cx.is_range_beyond_boundaries(range, *pat.ty()) {
             // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`.
-            non_exhaustive_tys.insert(pat.ty().inner());
+            special_tys.insert(*pat.ty());
         }
     }
-    pat.iter_fields()
-        .for_each(|field_pat| collect_non_exhaustive_tys(cx, field_pat, non_exhaustive_tys))
+    pat.iter_fields().for_each(|field_pat| collect_special_tys(cx, field_pat, special_tys))
 }
 
 fn report_adt_defined_here<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 261dcd52d71..658cc4c51a9 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -81,7 +81,7 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::PanicStrategy;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::TyCtxtInferExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index bfd505c0672..3655a677ba0 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -228,6 +228,7 @@ use rustc_middle::ty::{
     self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
     TypeVisitableExt, VtblEntry,
 };
+use rustc_middle::util::Providers;
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::EntryFnType;
 use rustc_session::Limit;
@@ -399,7 +400,7 @@ fn collect_items_rec<'tcx>(
                 let instance = Instance::mono(tcx, def_id);
 
                 // Sanity check whether this ended up being collected accidentally
-                debug_assert!(should_codegen_locally(tcx, instance));
+                debug_assert!(tcx.should_codegen_locally(instance));
 
                 let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
                 // Nested statics have no type.
@@ -431,7 +432,7 @@ fn collect_items_rec<'tcx>(
         }
         MonoItem::Fn(instance) => {
             // Sanity check whether this ended up being collected accidentally
-            debug_assert!(should_codegen_locally(tcx, instance));
+            debug_assert!(tcx.should_codegen_locally(instance));
 
             // Keep track of the monomorphization recursion depth
             recursion_depth_reset = Some(check_recursion_limit(
@@ -475,7 +476,7 @@ fn collect_items_rec<'tcx>(
                         }
                         hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
                             let instance = Instance::mono(tcx, *def_id);
-                            if should_codegen_locally(tcx, instance) {
+                            if tcx.should_codegen_locally(instance) {
                                 trace!("collecting static {:?}", def_id);
                                 used_items.push(dummy_spanned(MonoItem::Static(*def_id)));
                             }
@@ -712,7 +713,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 if let ty::Closure(def_id, args) = *source_ty.kind() {
                     let instance =
                         Instance::resolve_closure(self.tcx, def_id, args, ty::ClosureKind::FnOnce);
-                    if should_codegen_locally(self.tcx, instance) {
+                    if self.tcx.should_codegen_locally(instance) {
                         self.used_items.push(create_fn_mono_item(self.tcx, instance, span));
                     }
                 } else {
@@ -722,7 +723,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
             mir::Rvalue::ThreadLocalRef(def_id) => {
                 assert!(self.tcx.is_thread_local_static(def_id));
                 let instance = Instance::mono(self.tcx, def_id);
-                if should_codegen_locally(self.tcx, instance) {
+                if self.tcx.should_codegen_locally(instance) {
                     trace!("collecting thread-local static {:?}", def_id);
                     self.used_items.push(respan(span, MonoItem::Static(def_id)));
                 }
@@ -749,7 +750,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         let tcx = self.tcx;
         let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| {
             let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
-            if should_codegen_locally(tcx, instance) {
+            if tcx.should_codegen_locally(instance) {
                 this.used_items.push(create_fn_mono_item(tcx, instance, source));
             }
         };
@@ -783,7 +784,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
-                            if should_codegen_locally(self.tcx, instance) {
+                            if self.tcx.should_codegen_locally(instance) {
                                 trace!("collecting asm sym static {:?}", def_id);
                                 self.used_items.push(respan(source, MonoItem::Static(def_id)));
                             }
@@ -873,7 +874,7 @@ fn visit_instance_use<'tcx>(
     output: &mut MonoItems<'tcx>,
 ) {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
-    if !should_codegen_locally(tcx, instance) {
+    if !tcx.should_codegen_locally(instance) {
         return;
     }
     if let ty::InstanceKind::Intrinsic(def_id) = instance.def {
@@ -885,13 +886,13 @@ fn visit_instance_use<'tcx>(
             // codegen a call to that function without generating code for the function itself.
             let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None);
             let panic_instance = Instance::mono(tcx, def_id);
-            if should_codegen_locally(tcx, panic_instance) {
+            if tcx.should_codegen_locally(panic_instance) {
                 output.push(create_fn_mono_item(tcx, panic_instance, source));
             }
         } else if tcx.has_attr(def_id, sym::rustc_intrinsic) {
             // Codegen the fallback body of intrinsics with fallback bodies
             let instance = ty::Instance::new(def_id, instance.args);
-            if should_codegen_locally(tcx, instance) {
+            if tcx.should_codegen_locally(instance) {
                 output.push(create_fn_mono_item(tcx, instance, source));
             }
         }
@@ -930,7 +931,7 @@ fn visit_instance_use<'tcx>(
 
 /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
 /// can just link to the upstream crate and therefore don't need a mono item.
-pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
+fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool {
     let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
         return true;
     };
@@ -946,7 +947,7 @@ pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance
     }
 
     if tcx.is_reachable_non_generic(def_id)
-        || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some()
+        || instance.polymorphize(*tcx).upstream_monomorphization(*tcx).is_some()
     {
         // We can link to the item in question, no instance needed in this crate.
         return false;
@@ -1127,7 +1128,7 @@ fn create_mono_items_for_vtable_methods<'tcx>(
                     None
                 }
                 VtblEntry::Method(instance) => {
-                    Some(*instance).filter(|instance| should_codegen_locally(tcx, *instance))
+                    Some(*instance).filter(|instance| tcx.should_codegen_locally(*instance))
                 }
             })
             .map(|item| create_fn_mono_item(tcx, item, source));
@@ -1144,7 +1145,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
         GlobalAlloc::Static(def_id) => {
             assert!(!tcx.is_thread_local_static(def_id));
             let instance = Instance::mono(tcx, def_id);
-            if should_codegen_locally(tcx, instance) {
+            if tcx.should_codegen_locally(instance) {
                 trace!("collecting static {:?}", def_id);
                 output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
@@ -1162,7 +1163,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
             }
         }
         GlobalAlloc::Function { instance, .. } => {
-            if should_codegen_locally(tcx, instance) {
+            if tcx.should_codegen_locally(instance) {
                 trace!("collecting {:?} with {:#?}", alloc_id, instance);
                 output.push(create_fn_mono_item(tcx, instance, DUMMY_SP));
             }
@@ -1284,7 +1285,7 @@ fn visit_mentioned_item<'tcx>(
             if let ty::Closure(def_id, args) = *source_ty.kind() {
                 let instance =
                     Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce);
-                if should_codegen_locally(tcx, instance) {
+                if tcx.should_codegen_locally(instance) {
                     output.push(create_fn_mono_item(tcx, instance, span));
                 }
             } else {
@@ -1557,7 +1558,7 @@ fn create_mono_items_for_default_impls<'tcx>(
         let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP);
 
         let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
-        if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) {
+        if mono_item.node.is_instantiable(tcx) && tcx.should_codegen_locally(instance) {
             output.push(mono_item);
         }
     }
@@ -1613,3 +1614,7 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
 
     (mono_items, state.usage_map.into_inner())
 }
+
+pub fn provide(providers: &mut Providers) {
+    providers.hooks.should_codegen_locally = should_codegen_locally;
+}
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index aa3b4cd5b67..fc6e8e0d14f 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -5,14 +5,11 @@
 
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::bug;
-use rustc_middle::query::{Providers, TyCtxtAt};
+use rustc_middle::query::TyCtxtAt;
 use rustc_middle::traits;
 use rustc_middle::ty::adjustment::CustomCoerceUnsized;
-use rustc_middle::ty::Instance;
-use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::def_id::DefId;
-use rustc_span::def_id::LOCAL_CRATE;
+use rustc_middle::util::Providers;
 use rustc_span::ErrorGuaranteed;
 
 mod collector;
@@ -21,8 +18,6 @@ mod partitioning;
 mod polymorphize;
 mod util;
 
-use collector::should_codegen_locally;
-
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 fn custom_coerce_unsize_info<'tcx>(
@@ -47,34 +42,6 @@ fn custom_coerce_unsize_info<'tcx>(
     }
 }
 
-/// Returns whether a call from the current crate to the [`Instance`] would produce a call
-/// from `compiler_builtins` to a symbol the linker must resolve.
-///
-/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
-/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
-/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
-/// unlinkable calls.
-///
-/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
-pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-) -> bool {
-    fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
-            name.as_str().starts_with("llvm.")
-        } else {
-            false
-        }
-    }
-
-    let def_id = instance.def_id();
-    !def_id.is_local()
-        && tcx.is_compiler_builtins(LOCAL_CRATE)
-        && !is_llvm_intrinsic(tcx, def_id)
-        && !should_codegen_locally(tcx, instance)
-}
-
 pub fn provide(providers: &mut Providers) {
     partitioning::provide(providers);
     polymorphize::provide(providers);
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 9a7c488833a..8c7c5e0074a 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -112,9 +112,9 @@ use rustc_middle::mir::mono::{
     CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData,
     Visibility,
 };
-use rustc_middle::query::Providers;
 use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths};
 use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceKind, TyCtxt};
+use rustc_middle::util::Providers;
 use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
 use rustc_session::CodegenUnits;
 use rustc_span::symbol::Symbol;
@@ -1314,4 +1314,6 @@ pub fn provide(providers: &mut Providers) {
             .find(|cgu| cgu.name() == name)
             .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
     };
+
+    collector::provide(providers);
 }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index ce2fa83810f..9cbd989cc0e 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -34,7 +34,7 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
 use rustc_trait_selection::traits::ObligationCtxt;
 use std::cell::Cell;
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 603e98cfa92..6f59c782e06 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::{infer::TyCtxtInferExt, traits};
 
 use crate::errors::{
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d17ee8bff50..6ef2d69273e 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -40,9 +40,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcPatCtxt<'p, 'tcx>>;
 ///
 /// Use `.inner()` or deref to get to the `Ty<'tcx>`.
 #[repr(transparent)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct RevealedTy<'tcx>(Ty<'tcx>);
 
+impl<'tcx> fmt::Display for RevealedTy<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(fmt)
+    }
+}
+
 impl<'tcx> fmt::Debug for RevealedTy<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(fmt)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index dc7200465d9..51414d78596 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2763,7 +2763,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let res = match kind {
                 RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()),
                 RibKind::Normal => {
-                    if self.r.tcx.features().non_lifetime_binders {
+                    // FIXME(non_lifetime_binders): Stop special-casing
+                    // const params to error out here.
+                    if self.r.tcx.features().non_lifetime_binders
+                        && matches!(param.kind, GenericParamKind::Type { .. })
+                    {
                         Res::Def(def_kind, def_id.to_def_id())
                     } else {
                         Res::Err
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b64efadb261..2b30ca8a894 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -177,6 +177,7 @@ symbols! {
         CoerceUnsized,
         Command,
         ConstParamTy,
+        ConstParamTy_,
         Context,
         Continue,
         Copy,
@@ -336,6 +337,7 @@ symbols! {
         TyKind,
         Unknown,
         Unsize,
+        UnsizedConstParamTy,
         Upvars,
         Vec,
         VecDeque,
@@ -1689,6 +1691,7 @@ symbols! {
         rvalue_static_promotion,
         rwpi,
         s,
+        s390x_target_feature,
         safety,
         sanitize,
         sanitizer_cfi_generalize_pointers,
@@ -2001,6 +2004,8 @@ symbols! {
         unsafe_no_drop_flag,
         unsafe_pin_internals,
         unsize,
+        unsized_const_param_ty,
+        unsized_const_params,
         unsized_fn_params,
         unsized_locals,
         unsized_tuple_coercion,
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 6667efb14e2..4fb0323b6cf 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -4,6 +4,9 @@ use rustc_span::symbol::Symbol;
 /// Features that control behaviour of rustc, rather than the codegen.
 pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
 
+/// Features that require special handling when passing to LLVM.
+pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
+
 /// Stability information for target features.
 #[derive(Debug, Clone, Copy)]
 pub enum Stability {
@@ -397,6 +400,13 @@ const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     // tidy-alphabetical-end
 ];
 
+const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("backchain", Unstable(sym::s390x_target_feature)),
+    ("vector", Unstable(sym::s390x_target_feature)),
+    // tidy-alphabetical-end
+];
+
 /// When rustdoc is running, provide a list of all known features so that all their respective
 /// primitives may be documented.
 ///
@@ -414,6 +424,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
         .chain(BPF_ALLOWED_FEATURES.iter())
         .chain(CSKY_ALLOWED_FEATURES)
         .chain(LOONGARCH_ALLOWED_FEATURES)
+        .chain(IBMZ_ALLOWED_FEATURES)
         .cloned()
 }
 
@@ -431,6 +442,7 @@ impl super::spec::Target {
             "bpf" => BPF_ALLOWED_FEATURES,
             "csky" => CSKY_ALLOWED_FEATURES,
             "loongarch64" => LOONGARCH_ALLOWED_FEATURES,
+            "s390x" => IBMZ_ALLOWED_FEATURES,
             _ => &[],
         }
     }
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index f96bd985237..137850f31d3 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -1,3 +1,65 @@
+trait_selection_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
+    [true] , for some specific lifetime `'{$lifetime}`
+    *[false] {""}
+}
+trait_selection_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
+    [true] , for some specific lifetime `'{$lifetime}`
+    *[false] {""}
+}
+trait_selection_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
+    [true] , for some specific lifetime `'{$lifetime}`
+    *[false] {""}
+}
+
+trait_selection_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+trait_selection_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`
+
+trait_selection_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
+trait_selection_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+trait_selection_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
+trait_selection_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
+trait_selection_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
+trait_selection_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+trait_selection_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+trait_selection_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
+trait_selection_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
+trait_selection_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
 trait_selection_adjust_signature_borrow = consider adjusting the signature so it borrows its {$len ->
         [one] argument
         *[other] arguments
@@ -8,8 +70,48 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur
         *[other] arguments
     }
 
+trait_selection_ascribe_user_type_prove_predicate = ...so that the where clause holds
+
 trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment
 
+trait_selection_await_both_futures = consider `await`ing on both `Future`s
+trait_selection_await_future = consider `await`ing on the `Future`
+trait_selection_await_note = calling an async function returns a future
+
+trait_selection_but_calling_introduces = {$has_param_name ->
+    [true] `{$param_name}`
+    *[false] `fn` parameter
+} has {$lifetime_kind ->
+    [true] lifetime `{$lifetime}`
+    *[false] an anonymous lifetime `'_`
+} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement
+    .label1 = {$has_lifetime ->
+        [true] lifetime `{$lifetime}`
+        *[false] an anonymous lifetime `'_`
+    }
+    .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
+        [true] `impl` of `{$impl_path}`
+        *[false] inherent `impl`
+    }
+
+trait_selection_but_needs_to_satisfy = {$has_param_name ->
+    [true] `{$param_name}`
+    *[false] `fn` parameter
+} has {$has_lifetime ->
+    [true] lifetime `{$lifetime}`
+    *[false] an anonymous lifetime `'_`
+} but it needs to satisfy a `'static` lifetime requirement
+    .influencer = this data with {$has_lifetime ->
+        [true] lifetime `{$lifetime}`
+        *[false] an anonymous lifetime `'_`
+    }...
+    .require = {$spans_empty ->
+        *[true] ...is used and required to live as long as `'static` here
+        [false] ...and is required to live as long as `'static` here
+    }
+    .used_here = ...is used here...
+    .introduced_by_bound = `'static` lifetime requirement introduced by this bound
+
 trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here
 
 trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment
@@ -19,18 +121,67 @@ trait_selection_closure_kind_mismatch = expected a closure that implements the `
 
 trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here
 
+trait_selection_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
+trait_selection_consider_specifying_length = consider specifying the actual array length
+trait_selection_data_flows = ...but data{$label_var1_exists ->
+    [true] {" "}from `{$label_var1}`
+    *[false] {""}
+} flows{$label_var2_exists ->
+    [true] {" "}into `{$label_var2}`
+    *[false] {""}
+} here
+
+trait_selection_data_lifetime_flow = ...but data with one lifetime flows into the other here
+trait_selection_data_returned = ...but data{$label_var1_exists ->
+    [true] {" "}from `{$label_var1}`
+    *[false] {""}
+} is returned here
+
+trait_selection_declared_different = this parameter and the return type are declared with different lifetimes...
+trait_selection_declared_multiple = this type is declared with multiple lifetimes...
 trait_selection_disallowed_positional_argument = positional format arguments are not allowed here
     .help = only named format arguments with the name of one of the generic types are allowed in this context
 
+trait_selection_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+trait_selection_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
+trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement
+trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
+trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement
+
 trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
 
 trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
     .label = empty on-clause here
 
+trait_selection_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
+
+trait_selection_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
+
+trait_selection_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
+    .label = lifetime `{$named}` required
+
+trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
+    .label = lifetime `{$named}` required
+
+trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
+
+trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same
+trait_selection_fps_cast = consider casting to a fn pointer
+trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
+
+trait_selection_fps_items_are_distinct = fn items are distinct from fn pointers
+trait_selection_fps_remove_ref = consider removing the reference
+trait_selection_fps_use_ref = consider using a reference
+trait_selection_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
+
+trait_selection_full_type_written = the full type name has been written to '{$path}'
+
 trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to previous definition of `{$option_name}`
     .other_label = `{$option_name}` is first declared here
     .label = `{$option_name}` is already declared here
 
+trait_selection_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
+trait_selection_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
 trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
 
 trait_selection_invalid_format_specifier = invalid format specifier
@@ -39,13 +190,52 @@ trait_selection_invalid_format_specifier = invalid format specifier
 trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
     .label = invalid on-clause here
 
+trait_selection_label_bad = {$bad_kind ->
+    *[other] cannot infer type
+    [more_info] cannot infer {$prefix_kind ->
+        *[type] type for {$prefix}
+        [const_with_param] the value of const parameter
+        [const] the value of the constant
+    } `{$name}`{$has_parent ->
+        [true] {" "}declared on the {$parent_prefix} `{$parent_name}`
+        *[false] {""}
+    }
+}
+
+trait_selection_lf_bound_not_satisfied = lifetime bound not satisfied
+trait_selection_lifetime_mismatch = lifetime mismatch
+
+trait_selection_lifetime_param_suggestion = consider {$is_reuse ->
+    [true] reusing
+    *[false] introducing
+} a named lifetime parameter{$is_impl ->
+    [true] {" "}and update trait if needed
+    *[false] {""}
+}
+trait_selection_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
+
 trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute
     .help = only `message`, `note` and `label` are allowed as options
     .label = invalid option found here
 
+trait_selection_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
+trait_selection_meant_char_literal = if you meant to write a `char` literal, use single quotes
+trait_selection_meant_str_literal = if you meant to write a string literal, use double quotes
+trait_selection_mismatched_static_lifetime = incompatible lifetime on type
 trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute
     .help = at least one of the `message`, `note` and `label` options are expected
 
+trait_selection_more_targeted = {$has_param_name ->
+    [true] `{$param_name}`
+    *[false] `fn` parameter
+} has {$has_lifetime ->
+    [true] lifetime `{$lifetime}`
+    *[false] an anonymous lifetime `'_`
+} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
+
+trait_selection_msl_introduces_static = introduces a `'static` lifetime requirement
+trait_selection_msl_unmet_req = because this has an unmet lifetime requirement
+
 trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
         [none] {""}
        *[default] {" "}for type `{$self_desc}`
@@ -59,13 +249,214 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a
     .label = expected value here
     .note = eg `#[rustc_on_unimplemented(message="foo")]`
 
+trait_selection_nothing = {""}
+
+trait_selection_oc_cant_coerce = cannot coerce intrinsics to function pointers
+trait_selection_oc_closure_selfref = closure/coroutine type that references itself
+trait_selection_oc_const_compat = const not compatible with trait
+trait_selection_oc_fn_lang_correct_type = {$lang_item_name ->
+        [panic_impl] `#[panic_handler]`
+        *[lang_item_name] lang item `{$lang_item_name}`
+    } function has wrong type
+trait_selection_oc_fn_main_correct_type = `main` function has wrong type
+trait_selection_oc_fn_start_correct_type = `#[start]` function has wrong type
+trait_selection_oc_generic = mismatched types
+
+trait_selection_oc_if_else_different = `if` and `else` have incompatible types
+trait_selection_oc_intrinsic_correct_type = intrinsic has wrong type
+trait_selection_oc_match_compat = `match` arms have incompatible types
+trait_selection_oc_method_compat = method not compatible with trait
+trait_selection_oc_method_correct_type = mismatched `self` parameter type
+trait_selection_oc_no_diverge = `else` clause of `let...else` does not diverge
+trait_selection_oc_no_else = `if` may be missing an `else` clause
+trait_selection_oc_try_compat = `?` operator has incompatible types
+trait_selection_oc_type_compat = type not compatible with trait
+trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
+    .label = opaque type defined here
+
+trait_selection_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
+trait_selection_outlives_content = lifetime of reference outlives lifetime of borrowed content...
+
+trait_selection_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it
+trait_selection_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}`
+
+trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
+
+trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
+trait_selection_prlf_defined_without_sub = the lifetime defined here...
+trait_selection_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+trait_selection_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
+trait_selection_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here
+trait_selection_reborrow = ...so that reference does not outlive borrowed content
+trait_selection_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
+
+trait_selection_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
+trait_selection_region_explanation = {$pref_kind ->
+    *[should_not_happen] [{$pref_kind}]
+    [ref_valid_for] ...the reference is valid for
+    [content_valid_for] ...but the borrowed content is only valid for
+    [type_obj_valid_for] object type is valid for
+    [source_pointer_valid_for] source pointer is only valid for
+    [type_satisfy] type must satisfy
+    [type_outlive] type must outlive
+    [lf_param_instantiated_with] lifetime parameter instantiated with
+    [lf_param_must_outlive] but lifetime parameter must outlive
+    [lf_instantiated_with] lifetime instantiated with
+    [lf_must_outlive] but lifetime must outlive
+    [pointer_valid_for] the pointer is valid for
+    [data_valid_for] but the referenced data is only valid for
+    [empty] {""}
+}{$pref_kind ->
+    [empty] {""}
+    *[other] {" "}
+}{$desc_kind ->
+    *[should_not_happen] [{$desc_kind}]
+    [restatic] the static lifetime
+    [revar] lifetime {$desc_arg}
+    [as_defined] the lifetime `{$desc_arg}` as defined here
+    [as_defined_anon] the anonymous lifetime as defined here
+    [defined_here] the anonymous lifetime defined here
+    [defined_here_reg] the lifetime `{$desc_arg}` as defined here
+}{$suff_kind ->
+    *[should_not_happen] [{$suff_kind}]
+    [empty]{""}
+    [continues] ...
+    [req_by_binding] {" "}as required by this binding
+}
+
+trait_selection_relate_object_bound = ...so that it can be closed over into an object
+trait_selection_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
+    [true] ...
+    *[false] {""}
+}
+trait_selection_relate_param_bound_2 = ...that is required by this bound
+trait_selection_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
+trait_selection_ril_because_of = because of this returned expression
+trait_selection_ril_introduced_by = requirement introduced by this return type
+trait_selection_ril_introduced_here = `'static` requirement introduced here
+trait_selection_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
+
+trait_selection_source_kind_closure_return =
+    try giving this closure an explicit return type
+
+# coroutine_kind  may need to be translated
+trait_selection_source_kind_fully_qualified =
+    try using a fully qualified path to specify the expected types
+
+trait_selection_source_kind_subdiag_generic_label =
+    cannot infer {$is_type ->
+    [true] type
+    *[false] the value
+    } of the {$is_type ->
+    [true] type
+    *[false] const
+    } {$parent_exists ->
+    [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}`
+    *[false] parameter {$param_name}
+    }
+
+trait_selection_source_kind_subdiag_generic_suggestion =
+    consider specifying the generic {$arg_count ->
+    [one] argument
+    *[other] arguments
+    }
+
+trait_selection_source_kind_subdiag_let = {$kind ->
+    [with_pattern] consider giving `{$name}` an explicit type
+    [closure] consider giving this closure parameter an explicit type
+    *[other] consider giving this pattern a type
+}{$x_kind ->
+    [has_name] , where the {$prefix_kind ->
+        *[type] type for {$prefix}
+        [const_with_param] value of const parameter
+        [const] value of the constant
+    } `{$arg_name}` is specified
+    [underscore] , where the placeholders `_` are specified
+    *[empty] {""}
+}
+
+trait_selection_srs_add = consider returning the local binding `{$ident}`
+trait_selection_srs_add_one = consider returning one of these bindings
+
+trait_selection_srs_remove = consider removing this semicolon
+trait_selection_srs_remove_and_box = consider removing this semicolon and boxing the expressions
+trait_selection_stp_wrap_many = try wrapping the pattern in a variant of `{$path}`
+
+trait_selection_stp_wrap_one = try wrapping the pattern in `{$variant}`
+trait_selection_subtype = ...so that the {$requirement ->
+    [method_compat] method type is compatible with trait
+    [type_compat] associated type is compatible with trait
+    [const_compat] const is compatible with trait
+    [expr_assignable] expression is assignable
+    [if_else_different] `if` and `else` have incompatible types
+    [no_else] `if` missing an `else` returns `()`
+    [fn_main_correct_type] `main` function has the correct type
+    [fn_start_correct_type] `#[start]` function has the correct type
+    [fn_lang_correct_type] lang item function has the correct type
+    [intrinsic_correct_type] intrinsic has the correct type
+    [method_correct_type] method receiver has the correct type
+    *[other] types are compatible
+}
+trait_selection_subtype_2 = ...so that {$requirement ->
+    [method_compat] method type is compatible with trait
+    [type_compat] associated type is compatible with trait
+    [const_compat] const is compatible with trait
+    [expr_assignable] expression is assignable
+    [if_else_different] `if` and `else` have incompatible types
+    [no_else] `if` missing an `else` returns `()`
+    [fn_main_correct_type] `main` function has the correct type
+    [fn_start_correct_type] `#[start]` function has the correct type
+    [fn_lang_correct_type] lang item function has the correct type
+    [intrinsic_correct_type] intrinsic has the correct type
+    [method_correct_type] method receiver has the correct type
+    *[other] types are compatible
+}
+
+trait_selection_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
+
+trait_selection_suggest_add_let_for_letchains = consider adding `let`
+
+trait_selection_tid_consider_borrowing = consider borrowing this type parameter in the trait
+trait_selection_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+
+trait_selection_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 trait_selection_trait_has_no_impls = this trait has no implementations, consider adding one
 
+trait_selection_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
+    .found = found `{$found}`
+    .expected = expected `{$expected}`
+    .expected_found = expected signature `{$expected}`
+               {"   "}found signature `{$found}`
+
+trait_selection_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
+    .label_satisfy = doesn't satisfy where-clause
+    .label_where = due to a where-clause on `{$def_id}`...
+    .label_dup = implementation of `{$trait_def_id}` is not general enough
+
+trait_selection_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`
+
+trait_selection_tuple_trailing_comma = use a trailing comma to create a tuple with one element
+
 trait_selection_ty_alias_overflow = in case this is a recursive type alias, consider using a struct, enum, or union instead
+trait_selection_type_annotations_needed = {$source_kind ->
+    [closure] type annotations needed for the closure `{$source_name}`
+    [normal] type annotations needed for `{$source_name}`
+    *[other] type annotations needed
+}
+    .label = type must be known at this point
+
+trait_selection_types_declared_different = these two types are declared with different lifetimes...
+
 trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
 
 trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}`
     .help = expect either a generic argument name or {"`{Self}`"} as format argument
 
+trait_selection_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
+
+trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait
+
+trait_selection_where_remove = remove the `where` clause
 trait_selection_wrapped_parser_error = {$description}
     .label = {$label}
diff --git a/compiler/rustc_infer/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 9998fbca056..daabdec8f9e 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -46,14 +46,12 @@
 //! time of error detection.
 
 use std::borrow::Cow;
-use std::ops::{ControlFlow, Deref};
+use std::ops::ControlFlow;
 use std::path::PathBuf;
 use std::{cmp, fmt, iter};
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_errors::{
-    pluralize, Applicability, Diag, DiagCtxtHandle, DiagStyledString, IntoDiagArg, StringPart,
-};
+use rustc_errors::{pluralize, Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
@@ -72,23 +70,23 @@ use rustc_middle::ty::{
 use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 
+use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags};
 use crate::infer;
 use crate::infer::relate::{self, RelateResult, TypeRelation};
 use crate::infer::{InferCtxt, TypeTrace, ValuePairs};
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
-    PredicateObligation,
 };
 
 mod note_and_explain;
 mod suggest;
 
+pub mod need_type_info;
+pub mod nice_region_error;
 pub mod region;
 pub mod sub_relations;
 
-pub mod nice_region_error;
-
 /// Makes a valid string literal from a string by escaping special characters (" and \),
 /// unless they are already escaped.
 fn escape_literal(s: &str) -> String {
@@ -111,48 +109,59 @@ fn escape_literal(s: &str) -> String {
     escaped
 }
 
-/// A helper for building type related errors. The `typeck_results`
-/// field is only populated during an in-progress typeck.
-/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`.
-///
-/// You must only create this if you intend to actually emit an error (or
-/// perhaps a warning, though preferably not.) It provides a lot of utility
-/// 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,
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    // [Note-Type-error-reporting]
+    // An invariant is that anytime the expected or actual type is Error (the special
+    // error type, meaning that an error occurred when typechecking this expression),
+    // this is a derived error. The error cascaded from another error (that was already
+    // reported), so it's not useful to display it to the user.
+    // The following methods implement this logic.
+    // They check if either the actual or expected type is Error, and don't print the error
+    // in this case. The typechecker should only ever report type errors involving mismatched
+    // types using one of these methods, and should not call span_err directly for such
+    // errors.
+    pub fn type_error_struct_with_diag<M>(
+        &self,
+        sp: Span,
+        mk_diag: M,
+        actual_ty: Ty<'tcx>,
+    ) -> Diag<'a>
+    where
+        M: FnOnce(String) -> Diag<'a>,
+    {
+        let actual_ty = self.resolve_vars_if_possible(actual_ty);
+        debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
 
-    pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
+        let mut err = mk_diag(self.ty_to_string(actual_ty));
 
-    pub autoderef_steps:
-        Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
-}
+        // Don't report an error if actual type is `Error`.
+        if actual_ty.references_error() {
+            err.downgrade_to_delayed_bug();
+        }
 
-impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    pub fn dcx(&self) -> DiagCtxtHandle<'a> {
-        self.infcx.dcx()
+        err
     }
 
-    /// This is just to avoid a potential footgun of accidentally
-    /// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
-    #[deprecated(note = "you already have a `TypeErrCtxt`")]
-    #[allow(unused)]
-    pub fn err_ctxt(&self) -> ! {
-        bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call");
+    pub fn report_mismatched_types(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+        err: TypeError<'tcx>,
+    ) -> Diag<'a> {
+        self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
     }
-}
 
-impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
-    type Target = InferCtxt<'tcx>;
-    fn deref(&self) -> &InferCtxt<'tcx> {
-        self.infcx
+    pub fn report_mismatched_consts(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        expected: ty::Const<'tcx>,
+        actual: ty::Const<'tcx>,
+        err: TypeError<'tcx>,
+    ) -> Diag<'a> {
+        self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
     }
-}
 
-impl<'tcx> InferCtxt<'tcx> {
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let (def_id, args) = match *ty.kind() {
             ty::Alias(_, ty::AliasTy { def_id, args, .. })
@@ -189,9 +198,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     .flatten()
             })
     }
-}
 
-impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// Adds a note if the types come from similarly named crates
     fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) {
         use hir::def_id::CrateNum;
@@ -2190,32 +2197,3 @@ impl TyCategory {
         }
     }
 }
-
-impl<'tcx> InferCtxt<'tcx> {
-    /// Given a [`hir::Block`], get the span of its last expression or
-    /// statement, peeling off any inner blocks.
-    pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
-        let block = block.innermost_block();
-        if let Some(expr) = &block.expr {
-            expr.span
-        } else if let Some(stmt) = block.stmts.last() {
-            // possibly incorrect trailing `;` in the else arm
-            stmt.span
-        } else {
-            // empty block; point at its entirety
-            block.span
-        }
-    }
-
-    /// Given a [`hir::HirId`] for a block, get the span of its last expression
-    /// or statement, peeling off any inner blocks.
-    pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
-        match self.tcx.hir_node(hir_id) {
-            hir::Node::Block(blk) => self.find_block_span(blk),
-            // The parser was in a weird state if either of these happen, but
-            // it's better not to panic.
-            hir::Node::Expr(e) => e.span,
-            _ => rustc_span::DUMMY_SP,
-        }
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 4f3dcd9043f..56ea70bcf1d 100644
--- a/compiler/rustc_infer/src/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -1,4 +1,4 @@
-use crate::error_reporting::infer::TypeErrCtxt;
+use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{
     AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError,
     SourceKindMultiSuggestion, SourceKindSubdiag,
@@ -13,7 +13,6 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::{
@@ -183,9 +182,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
             warn!("resolved ty var in error message");
         }
 
-        let mut infcx_inner = infcx.inner.borrow_mut();
-        let ty_vars = infcx_inner.type_variables();
-        let var_origin = ty_vars.var_origin(ty_vid);
+        let var_origin = infcx.type_var_origin(ty_vid);
         if let Some(def_id) = var_origin.param_def_id
             // The `Self` param of a trait has the def-id of the trait,
             // since it's a synthetic parameter.
@@ -206,24 +203,8 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
         }
     };
     printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
-    let const_getter = move |ct_vid| match infcx
-        .inner
-        .borrow_mut()
-        .const_unification_table()
-        .probe_value(ct_vid)
-    {
-        ConstVariableValue::Known { value: _ } => {
-            warn!("resolved const var in error message");
-            None
-        }
-        ConstVariableValue::Unknown { origin, universe: _ } => {
-            if let Some(def_id) = origin.param_def_id {
-                Some(infcx.tcx.item_name(def_id))
-            } else {
-                None
-            }
-        }
-    };
+    let const_getter =
+        move |ct_vid| Some(infcx.tcx.item_name(infcx.const_var_origin(ct_vid)?.param_def_id?));
     printer.const_infer_name_resolver = Some(Box::new(const_getter));
     printer
 }
@@ -289,7 +270,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
     format!("fn({args}){ret}")
 }
 
-impl<'tcx> InferCtxt<'tcx> {
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// Extracts data used by diagnostic for either types or constants
     /// which were stuck during inference.
     pub fn extract_inference_diagnostics_data(
@@ -300,9 +281,7 @@ impl<'tcx> InferCtxt<'tcx> {
         match arg.unpack() {
             GenericArgKind::Type(ty) => {
                 if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
-                    let mut inner = self.inner.borrow_mut();
-                    let ty_vars = &inner.type_variables();
-                    let var_origin = ty_vars.var_origin(ty_vid);
+                    let var_origin = self.infcx.type_var_origin(ty_vid);
                     if let Some(def_id) = var_origin.param_def_id
                         // The `Self` param of a trait has the def-id of the trait,
                         // since it's a synthetic parameter.
@@ -332,13 +311,7 @@ impl<'tcx> InferCtxt<'tcx> {
             }
             GenericArgKind::Const(ct) => {
                 if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
-                    let origin =
-                        match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
-                            ConstVariableValue::Known { value } => {
-                                bug!("resolved infer var: {vid:?} {value}")
-                            }
-                            ConstVariableValue::Unknown { origin, universe: _ } => origin,
-                        };
+                    let origin = self.const_var_origin(vid).expect("expected unresolved const var");
                     if let Some(def_id) = origin.param_def_id {
                         return InferenceDiagnosticsData {
                             name: self.tcx.item_name(def_id).to_string(),
@@ -391,7 +364,7 @@ impl<'tcx> InferCtxt<'tcx> {
         span: Span,
         arg_data: InferenceDiagnosticsData,
         error_code: TypeAnnotationNeeded,
-    ) -> Diag<'_> {
+    ) -> Diag<'a> {
         let source_kind = "other";
         let source_name = "";
         let failure_span = None;
@@ -434,9 +407,7 @@ impl<'tcx> InferCtxt<'tcx> {
             }),
         }
     }
-}
 
-impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     #[instrument(level = "debug", skip(self, error_code))]
     pub fn emit_inference_failure_err(
         &self,
@@ -453,7 +424,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             // If we don't have any typeck results we're outside
             // of a body, so we won't be able to get better info
             // here.
-            return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code);
+            return self.bad_inference_failure_err(failure_span, arg_data, error_code);
         };
 
         let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg);
@@ -465,7 +436,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
 
         let Some(InferSource { span, kind }) = local_visitor.infer_source else {
-            return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code);
+            return self.bad_inference_failure_err(failure_span, arg_data, error_code);
         };
 
         let (source_kind, name, path) = kind.ty_localized_msg(self);
@@ -887,7 +858,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                 use ty::InferConst::*;
                 match (inner_ct.kind(), target_ct.kind()) {
                     (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => {
-                        self.tecx.inner.borrow_mut().const_unification_table().unioned(a_vid, b_vid)
+                        self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid)
                     }
                     _ => false,
                 }
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs
index 74dcde03639..74dcde03639 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
index b91b755d683..b91b755d683 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
index 550cc455e01..550cc455e01 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
index ced4c384f02..b83ecd8320c 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
@@ -1,4 +1,4 @@
-use crate::error_reporting::infer::TypeErrCtxt;
+use crate::error_reporting::TypeErrCtxt;
 use crate::infer::RegionResolutionError;
 use crate::infer::RegionResolutionError::*;
 use rustc_errors::{Diag, ErrorGuaranteed};
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
index d1802d2f5ee..d1802d2f5ee 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
index 476ac3f1720..476ac3f1720 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
index e9f17a3e3e2..e9f17a3e3e2 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index ce157ff3dc8..ce157ff3dc8 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
index c58c7e13551..c58c7e13551 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
index 30fa98c5526..30fa98c5526 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
index aeb3049c2ae..aeb3049c2ae 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/note.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index d5e7de897d0..1ff2fca83fa 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -1,4 +1,3 @@
-use super::TypeErrCtxt;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, Diag, MultiSpan};
 use rustc_hir as hir;
@@ -12,6 +11,8 @@ use rustc_middle::{
 };
 use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol};
 
+use crate::error_reporting::TypeErrCtxt;
+
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     pub fn note_and_explain_type_err(
         &self,
diff --git a/compiler/rustc_infer/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 5d41bb5d271..3cee8ff5f4c 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -18,7 +18,8 @@ use rustc_type_ir::Upcast as _;
 
 use super::nice_region_error::find_anon_type;
 use super::{nice_region_error, ObligationCauseAsDiagArg};
-use crate::error_reporting::infer::{ObligationCauseExt as _, TypeErrCtxt};
+use crate::error_reporting::infer::ObligationCauseExt as _;
+use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{
     self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound,
     OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
@@ -224,16 +225,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             .add_to_diag(err),
             infer::Reborrow(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err)
+                RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow }
+                    .add_to_diag(err)
             }
             infer::RelateObjectBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
+                RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound }
                     .add_to_diag(err);
             }
             infer::ReferenceOutlivesReferent(ty, span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer_reference_outlives_referent,
+                    msg: fluent::trait_selection_reference_outlives_referent,
                     name: &self.ty_to_string(ty),
                     continues: false,
                 }
@@ -242,23 +244,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             infer::RelateParamBound(span, ty, opt_span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer_relate_param_bound,
+                    msg: fluent::trait_selection_relate_param_bound,
                     name: &self.ty_to_string(ty),
                     continues: opt_span.is_some(),
                 }
                 .add_to_diag(err);
                 if let Some(span) = opt_span {
-                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
-                        .add_to_diag(err);
+                    RegionOriginNote::Plain {
+                        span,
+                        msg: fluent::trait_selection_relate_param_bound_2,
+                    }
+                    .add_to_diag(err);
                 }
             }
             infer::RelateRegionParamBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
-                    .add_to_diag(err);
+                RegionOriginNote::Plain {
+                    span,
+                    msg: fluent::trait_selection_relate_region_param_bound,
+                }
+                .add_to_diag(err);
             }
             infer::CompareImplItemObligation { span, .. } => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
-                    .add_to_diag(err);
+                RegionOriginNote::Plain {
+                    span,
+                    msg: fluent::trait_selection_compare_impl_item_obligation,
+                }
+                .add_to_diag(err);
             }
             infer::CheckAssociatedTypeBounds { ref parent, .. } => {
                 self.note_region_origin(err, parent);
@@ -266,7 +277,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             infer::AscribeUserTypeProvePredicate(span) => {
                 RegionOriginNote::Plain {
                     span,
-                    msg: fluent::infer_ascribe_user_type_prove_predicate,
+                    msg: fluent::trait_selection_ascribe_user_type_prove_predicate,
                 }
                 .add_to_diag(err);
             }
@@ -445,7 +456,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 })
             }
             infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
-                let mut err = self.infcx.report_extra_impl_obligation(
+                let mut err = self.report_extra_impl_obligation(
                     span,
                     impl_item_def_id,
                     trait_item_def_id,
@@ -645,7 +656,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             trait_item_def_id,
         }) = origin
         {
-            return self.infcx.report_extra_impl_obligation(
+            return self.report_extra_impl_obligation(
                 span,
                 impl_item_def_id,
                 trait_item_def_id,
diff --git a/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs
index ef26a8ff7b8..ef26a8ff7b8 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs
diff --git a/compiler/rustc_infer/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 4d11ab9fac6..1ef32d110b3 100644
--- a/compiler/rustc_infer/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -17,14 +17,13 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
 use rustc_span::{sym, Span};
 
+use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{
     ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
     FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
     SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
 };
 
-use super::TypeErrCtxt;
-
 #[derive(Clone, Copy)]
 pub enum SuggestAsRefKind {
     Option,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
index f6ac8fc7b61..cb7efeaae0b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
@@ -1 +1,73 @@
+use std::ops::Deref;
+
+use rustc_errors::DiagCtxtHandle;
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::PredicateObligation;
+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;
+
+/// A helper for building type related errors. The `typeck_results`
+/// field is only populated during an in-progress typeck.
+/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`.
+///
+/// You must only create this if you intend to actually emit an error (or
+/// perhaps a warning, though preferably not.) It provides a lot of utility
+/// 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,
+
+    pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
+
+    pub autoderef_steps:
+        Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
+}
+
+#[extension(pub trait InferCtxtErrorExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
+    /// Creates a `TypeErrCtxt` for emitting various inference errors.
+    /// During typeck, use `FnCtxt::err_ctxt` instead.
+    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),
+            autoderef_steps: Box::new(|ty| {
+                debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
+                vec![(ty, vec![])]
+            }),
+        }
+    }
+}
+
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    pub fn dcx(&self) -> DiagCtxtHandle<'a> {
+        self.infcx.dcx()
+    }
+
+    /// This is just to avoid a potential footgun of accidentally
+    /// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
+    #[deprecated(note = "you already have a `TypeErrCtxt`")]
+    #[allow(unused)]
+    pub fn err_ctxt(&self) -> ! {
+        bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call");
+    }
+}
+
+impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
+    type Target = InferCtxt<'tcx>;
+    fn deref(&self) -> &InferCtxt<'tcx> {
+        self.infcx
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index deab0451ccb..72a4d4c1205 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -8,21 +8,17 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor as _;
 use rustc_hir::LangItem;
-use rustc_infer::error_reporting::infer::TypeErrCtxt;
-use rustc_infer::infer::need_type_info::TypeAnnotationNeeded;
 use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
 use rustc_infer::traits::util::elaborate;
 use rustc_infer::traits::{
     Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation,
 };
-use rustc_macros::extension;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _};
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 
-use crate::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
-use crate::error_reporting::traits::{
-    to_pretty_impl_header, FindExprBySpan, InferCtxtPrivExt as _,
-};
+use crate::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
+use crate::error_reporting::traits::{to_pretty_impl_header, FindExprBySpan};
+use crate::error_reporting::TypeErrCtxt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::ObligationCtxt;
 
@@ -153,10 +149,12 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>(
     ambiguities
 }
 
-#[extension(pub trait TypeErrCtxtAmbiguityExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "debug")]
-    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed {
+    pub(super) fn maybe_report_ambiguity(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> ErrorGuaranteed {
         // Unable to successfully determine, probably means
         // insufficient type information, but could mean
         // ambiguous impls. The latter *ought* to be a
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 0d040ddbacb..85b37ff3260 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1,6 +1,9 @@
-use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
-use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
+use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote};
+use super::suggestions::get_explanation_based_on_obligation;
+use crate::error_reporting::infer::TyCategory;
 use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
+use crate::error_reporting::traits::report_object_safety_error;
+use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{
     AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
 };
@@ -24,10 +27,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_hir::{self as hir, LangItem};
-use rustc_infer::error_reporting::infer::TyCategory;
-use rustc_infer::error_reporting::infer::TypeErrCtxt;
 use rustc_infer::infer::{InferOk, TypeTrace};
-use rustc_macros::extension;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::traits::SignatureMismatchData;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -49,14 +49,11 @@ use super::{
     ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst,
 };
 
-pub use rustc_infer::traits::error_reporting::*;
-
-#[extension(pub trait TypeErrCtxtSelectionErrExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// The `root_obligation` parameter should be the `root_obligation` field
     /// from a `FulfillmentError`. If no `FulfillmentError` is available,
     /// then it should be the same as `obligation`.
-    fn report_selection_error(
+    pub fn report_selection_error(
         &self,
         mut obligation: PredicateObligation<'tcx>,
         root_obligation: &PredicateObligation<'tcx>,
@@ -682,9 +679,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 }
 
-#[extension(pub(super) trait TypeErrCtxtExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool {
+    pub(super) fn apply_do_not_recommend(
+        &self,
+        obligation: &mut PredicateObligation<'tcx>,
+    ) -> bool {
         let mut base_cause = obligation.cause.code().clone();
         let mut applied_do_not_recommend = false;
         loop {
@@ -1142,7 +1141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 }
 
-#[extension(pub(super) trait InferCtxtPrivExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn can_match_trait(
         &self,
@@ -1182,7 +1180,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     // returns if `cond` not occurring implies that `error` does not occur - i.e., that
     // `error` occurring implies that `cond` occurs.
     #[instrument(level = "debug", skip(self), ret)]
-    fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
+    pub(super) fn error_implies(
+        &self,
+        cond: ty::Predicate<'tcx>,
+        error: ty::Predicate<'tcx>,
+    ) -> bool {
         if cond == error {
             return true;
         }
@@ -1205,7 +1207,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip_all)]
-    fn report_projection_error(
+    pub(super) fn report_projection_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
         error: &MismatchedProjectionTypes<'tcx>,
@@ -1455,7 +1457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn fuzzy_match_tys(
+    pub fn fuzzy_match_tys(
         &self,
         mut a: Ty<'tcx>,
         mut b: Ty<'tcx>,
@@ -1535,7 +1537,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str {
+    pub(super) fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str {
         match kind {
             hir::ClosureKind::Closure => "a closure",
             hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine",
@@ -1585,7 +1587,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn find_similar_impl_candidates(
+    pub(super) fn find_similar_impl_candidates(
         &self,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Vec<ImplCandidate<'tcx>> {
@@ -1615,7 +1617,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         candidates
     }
 
-    fn report_similar_impl_candidates(
+    pub(super) fn report_similar_impl_candidates(
         &self,
         impl_candidates: &[ImplCandidate<'tcx>],
         trait_ref: ty::PolyTraitRef<'tcx>,
@@ -1989,7 +1991,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// `trait_ref`.
     ///
     /// For this to work, `new_self_ty` must have no escaping bound variables.
-    fn mk_trait_obligation_with_new_self_ty(
+    pub(super) fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
@@ -2041,7 +2043,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         })
     }
 
-    fn note_obligation_cause(&self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>) {
+    pub fn note_obligation_cause(
+        &self,
+        err: &mut Diag<'_>,
+        obligation: &PredicateObligation<'tcx>,
+    ) {
         // First, attempt to add note to this error with an async-await-specific
         // message, and fall back to regular note otherwise.
         if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
@@ -2067,7 +2073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn is_recursive_obligation(
+    pub(super) fn is_recursive_obligation(
         &self,
         obligated_types: &mut Vec<Ty<'tcx>>,
         cause_code: &ObligationCauseCode<'tcx>,
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 16dfa27b75a..10624786bae 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -5,28 +5,24 @@ pub mod on_unimplemented;
 mod overflow;
 pub mod suggestions;
 
-use std::iter;
+use std::{fmt, iter};
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_hir::def_id::DefId;
+use rustc_errors::{struct_span_code_err, Applicability, Diag, MultiSpan, E0038, E0276};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{self as hir, LangItem};
-use rustc_infer::error_reporting::infer::TypeErrCtxt;
 use rustc_infer::traits::{
-    Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError,
+    ObjectSafetyViolation, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+    SelectionError,
 };
-use rustc_macros::extension;
-use rustc_middle::ty::print::PrintTraitRefExt as _;
+use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{ErrorGuaranteed, ExpnKind, Span};
 
-use ambiguity::TypeErrCtxtAmbiguityExt as _;
-use fulfillment_errors::TypeErrCtxtExt as _;
-use suggestions::TypeErrCtxtExt as _;
-
+use crate::error_reporting::TypeErrCtxt;
 use crate::traits::{FulfillmentError, FulfillmentErrorCode};
 
-pub use self::fulfillment_errors::*;
 pub use self::infer_ctxt_ext::*;
 pub use self::overflow::*;
 
@@ -137,9 +133,8 @@ pub enum DefIdOrName {
     Name(&'static str),
 }
 
-#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    fn report_fulfillment_errors(
+    pub fn report_fulfillment_errors(
         &self,
         mut errors: Vec<FulfillmentError<'tcx>>,
     ) -> ErrorGuaranteed {
@@ -383,3 +378,194 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
     w.push(';');
     Some(w)
 }
+
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    pub fn report_extra_impl_obligation(
+        &self,
+        error_span: Span,
+        impl_item_def_id: LocalDefId,
+        trait_item_def_id: DefId,
+        requirement: &dyn fmt::Display,
+    ) -> Diag<'a> {
+        let mut err = struct_span_code_err!(
+            self.dcx(),
+            error_span,
+            E0276,
+            "impl has stricter requirements than trait"
+        );
+
+        if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
+            if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) {
+                let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
+                err.span_label(span, format!("definition of `{item_name}` from trait"));
+            }
+        }
+
+        err.span_label(error_span, format!("impl has extra requirement {requirement}"));
+
+        err
+    }
+}
+
+pub fn report_object_safety_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    span: Span,
+    hir_id: Option<hir::HirId>,
+    trait_def_id: DefId,
+    violations: &[ObjectSafetyViolation],
+) -> Diag<'tcx> {
+    let trait_str = tcx.def_path_str(trait_def_id);
+    let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
+        hir::Node::Item(item) => Some(item.ident.span),
+        _ => None,
+    });
+    let mut err = struct_span_code_err!(
+        tcx.dcx(),
+        span,
+        E0038,
+        "the trait `{}` cannot be made into an object",
+        trait_str
+    );
+    err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
+
+    if let Some(hir_id) = hir_id
+        && let hir::Node::Ty(ty) = tcx.hir_node(hir_id)
+        && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
+    {
+        let mut hir_id = hir_id;
+        while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
+            hir_id = ty.hir_id;
+        }
+        if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
+            // Do not suggest `impl Trait` when dealing with things like super-traits.
+            err.span_suggestion_verbose(
+                ty.span.until(trait_ref.span),
+                "consider using an opaque type instead",
+                "impl ",
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+    let mut reported_violations = FxIndexSet::default();
+    let mut multi_span = vec![];
+    let mut messages = vec![];
+    for violation in violations {
+        if let ObjectSafetyViolation::SizedSelf(sp) = &violation
+            && !sp.is_empty()
+        {
+            // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
+            // with a `Span`.
+            reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
+        }
+        if reported_violations.insert(violation.clone()) {
+            let spans = violation.spans();
+            let msg = if trait_span.is_none() || spans.is_empty() {
+                format!("the trait cannot be made into an object because {}", violation.error_msg())
+            } else {
+                format!("...because {}", violation.error_msg())
+            };
+            if spans.is_empty() {
+                err.note(msg);
+            } else {
+                for span in spans {
+                    multi_span.push(span);
+                    messages.push(msg.clone());
+                }
+            }
+        }
+    }
+    let has_multi_span = !multi_span.is_empty();
+    let mut note_span = MultiSpan::from_spans(multi_span.clone());
+    if let (Some(trait_span), true) = (trait_span, has_multi_span) {
+        note_span.push_span_label(trait_span, "this trait cannot be made into an object...");
+    }
+    for (span, msg) in iter::zip(multi_span, messages) {
+        note_span.push_span_label(span, msg);
+    }
+    err.span_note(
+        note_span,
+        "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \
+         to be resolvable dynamically; for more information visit \
+         <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+    );
+
+    // Only provide the help if its a local trait, otherwise it's not actionable.
+    if trait_span.is_some() {
+        let mut reported_violations: Vec<_> = reported_violations.into_iter().collect();
+        reported_violations.sort();
+
+        let mut potential_solutions: Vec<_> =
+            reported_violations.into_iter().map(|violation| violation.solution()).collect();
+        potential_solutions.sort();
+        // Allows us to skip suggesting that the same item should be moved to another trait multiple times.
+        potential_solutions.dedup();
+        for solution in potential_solutions {
+            solution.add_to(&mut err);
+        }
+    }
+
+    let impls_of = tcx.trait_impls_of(trait_def_id);
+    let impls = if impls_of.blanket_impls().is_empty() {
+        impls_of
+            .non_blanket_impls()
+            .values()
+            .flatten()
+            .filter(|def_id| {
+                !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..))
+            })
+            .collect::<Vec<_>>()
+    } else {
+        vec![]
+    };
+    let externally_visible = if !impls.is_empty()
+        && let Some(def_id) = trait_def_id.as_local()
+        // We may be executing this during typeck, which would result in cycle
+        // if we used effective_visibilities query, which looks into opaque types
+        // (and therefore calls typeck).
+        && tcx.resolutions(()).effective_visibilities.is_exported(def_id)
+    {
+        true
+    } else {
+        false
+    };
+    match &impls[..] {
+        [] => {}
+        _ if impls.len() > 9 => {}
+        [only] if externally_visible => {
+            err.help(with_no_trimmed_paths!(format!(
+                "only type `{}` is seen to implement the trait in this crate, consider using it \
+                 directly instead",
+                tcx.type_of(*only).instantiate_identity(),
+            )));
+        }
+        [only] => {
+            err.help(with_no_trimmed_paths!(format!(
+                "only type `{}` implements the trait, consider using it directly instead",
+                tcx.type_of(*only).instantiate_identity(),
+            )));
+        }
+        impls => {
+            let types = impls
+                .iter()
+                .map(|t| {
+                    with_no_trimmed_paths!(format!("  {}", tcx.type_of(*t).instantiate_identity(),))
+                })
+                .collect::<Vec<_>>();
+            err.help(format!(
+                "the following types implement the trait, consider defining an enum where each \
+                 variant holds one of these types, implementing `{}` for this new enum and using \
+                 it instead:\n{}",
+                trait_str,
+                types.join("\n"),
+            ));
+        }
+    }
+    if externally_visible {
+        err.note(format!(
+            "`{trait_str}` can be implemented in other crates; if you want to support your users \
+             passing their own types here, you can't refer to a specific type",
+        ));
+    }
+
+    err
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index a448e1924c8..f65de590ccf 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -1,5 +1,5 @@
 use super::{ObligationCauseCode, PredicateObligation};
-use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt;
+use crate::error_reporting::TypeErrCtxt;
 use crate::errors::{
     EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
 };
@@ -13,8 +13,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_infer::error_reporting::infer::TypeErrCtxt;
-use rustc_macros::{extension, LintDiagnostic};
+use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::GenericArgsRef;
@@ -41,7 +40,6 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
     sym::Trait,
 ];
 
-#[extension(pub trait TypeErrCtxtExt<'tcx>)]
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn impl_similar_to(
         &self,
@@ -109,7 +107,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
-    fn on_unimplemented_note(
+    pub fn on_unimplemented_note(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         obligation: &PredicateObligation<'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 fe1771f9096..16fbff7816a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
@@ -5,17 +5,14 @@ use rustc_errors::{
 };
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_infer::error_reporting::infer::TypeErrCtxt;
 use rustc_infer::traits::{Obligation, PredicateObligation};
-use rustc_macros::extension;
 use rustc_middle::ty::print::{FmtPrinter, Print};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::Limit;
 use rustc_span::Span;
 use rustc_type_ir::Upcast;
 
-use super::InferCtxtPrivExt;
-use crate::error_reporting::traits::suggestions::TypeErrCtxtExt;
+use crate::error_reporting::TypeErrCtxt;
 
 pub enum OverflowCause<'tcx> {
     DeeplyNormalize(ty::AliasTerm<'tcx>),
@@ -38,7 +35,6 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
     ));
 }
 
-#[extension(pub trait TypeErrCtxtOverflowExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// Reports that an overflow has occurred and halts compilation. We
     /// halt compilation unconditionally because it is important that
@@ -46,7 +42,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// whose result could not be truly determined and thus we can't say
     /// if the program type checks or not -- and they are unusual
     /// occurrences in any case.
-    fn report_overflow_error(
+    pub fn report_overflow_error(
         &self,
         cause: OverflowCause<'tcx>,
         span: Span,
@@ -59,7 +55,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         FatalError.raise();
     }
 
-    fn build_overflow_error(
+    pub fn build_overflow_error(
         &self,
         cause: OverflowCause<'tcx>,
         span: Span,
@@ -132,7 +128,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// whose result could not be truly determined and thus we can't say
     /// if the program type checks or not -- and they are unusual
     /// occurrences in any case.
-    fn report_overflow_obligation<T>(
+    pub fn report_overflow_obligation<T>(
         &self,
         obligation: &Obligation<'tcx, T>,
         suggest_increasing_limit: bool,
@@ -165,7 +161,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// that we can give a more helpful error message (and, in particular,
     /// we do not suggest increasing the overflow limit, which is not
     /// going to help).
-    fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+    pub fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
         let cycle = self.resolve_vars_if_possible(cycle.to_owned());
         assert!(!cycle.is_empty());
 
@@ -179,7 +175,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         );
     }
 
-    fn report_overflow_no_abort(
+    pub fn report_overflow_no_abort(
         &self,
         obligation: PredicateObligation<'tcx>,
         suggest_increasing_limit: bool,
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 ffc8839435e..885216e6216 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -5,11 +5,10 @@ use super::{
     PredicateObligation,
 };
 
+use crate::error_reporting::TypeErrCtxt;
 use crate::errors;
-use crate::infer::InferCtxt;
 use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt};
 
-use hir::def::CtorOf;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
@@ -17,15 +16,15 @@ use rustc_errors::{
     Style, SuggestionStyle,
 };
 use rustc_hir as hir;
+use rustc_hir::def::CtorOf;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::is_range_literal;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node};
-use rustc_infer::error_reporting::infer::TypeErrCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
-use rustc_macros::extension;
 use rustc_middle::hir::map;
 use rustc_middle::traits::IsConstable;
 use rustc_middle::ty::error::TypeError;
@@ -44,7 +43,6 @@ use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::iter;
 
-use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt;
 use crate::infer::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_middle::ty::print::{
@@ -241,9 +239,8 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
     }
 }
 
-#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    fn suggest_restricting_param_bound(
+    pub fn suggest_restricting_param_bound(
         &self,
         err: &mut Diag<'_>,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
@@ -453,7 +450,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// When after several dereferencing, the reference satisfies the trait
     /// bound. This function provides dereference suggestion for this
     /// specific situation.
-    fn suggest_dereferences(
+    pub(super) fn suggest_dereferences(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -782,7 +779,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// We tried to apply the bound to an `fn` or closure. Check whether calling it would
     /// evaluate to a type that *would* satisfy the trait bound. If it would, suggest calling
     /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
-    fn suggest_fn_call(
+    pub(super) fn suggest_fn_call(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -898,7 +895,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         true
     }
 
-    fn check_for_binding_assigned_block_without_tail_expression(
+    pub(super) fn check_for_binding_assigned_block_without_tail_expression(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -974,7 +971,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_add_clone_to_arg(
+    pub(super) fn suggest_add_clone_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -1074,7 +1071,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// Extracts information about a callable type for diagnostics. This is a
     /// heuristic -- it doesn't necessarily mean that a type is always callable,
     /// because the callable type must also be well-formed to be called.
-    fn extract_callable_info(
+    pub fn extract_callable_info(
         &self,
         body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
@@ -1200,7 +1197,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
     }
 
-    fn suggest_add_reference_to_arg(
+    pub(super) fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -1422,7 +1419,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 
     // Suggest borrowing the type
-    fn suggest_borrowing_for_object_cast(
+    pub(super) fn suggest_borrowing_for_object_cast(
         &self,
         err: &mut Diag<'_>,
         obligation: &PredicateObligation<'tcx>,
@@ -1457,7 +1454,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
     /// suggest removing these references until we reach a type that implements the trait.
-    fn suggest_remove_reference(
+    pub(super) fn suggest_remove_reference(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -1578,7 +1575,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         false
     }
 
-    fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>) {
+    pub(super) fn suggest_remove_await(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut Diag<'_>,
+    ) {
         let hir = self.tcx.hir();
         if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives()
             && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id)
@@ -1644,7 +1645,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     /// Check if the trait bound is implemented for a different mutability and note it in the
     /// final error.
-    fn suggest_change_mut(
+    pub(super) fn suggest_change_mut(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -1720,7 +1721,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_semicolon_removal(
+    pub(super) fn suggest_semicolon_removal(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -1762,7 +1763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         false
     }
 
-    fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
+    pub(super) fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
         let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. }) =
             self.tcx.hir_node_by_def_id(obligation.cause.body_id)
         else {
@@ -1775,7 +1776,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if
     /// applicable and signal that the error has been expanded appropriately and needs to be
     /// emitted.
-    fn suggest_impl_trait(
+    pub(super) fn suggest_impl_trait(
         &self,
         err: &mut Diag<'_>,
         obligation: &PredicateObligation<'tcx>,
@@ -1865,7 +1866,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         true
     }
 
-    fn point_at_returns_when_relevant(
+    pub(super) fn point_at_returns_when_relevant(
         &self,
         err: &mut Diag<'_>,
         obligation: &PredicateObligation<'tcx>,
@@ -1897,7 +1898,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn report_closure_arg_mismatch(
+    pub(super) fn report_closure_arg_mismatch(
         &self,
         span: Span,
         found_span: Option<Span>,
@@ -2176,7 +2177,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_fully_qualified_path(
+    pub(super) fn suggest_fully_qualified_path(
         &self,
         err: &mut Diag<'_>,
         item_def_id: DefId,
@@ -2243,7 +2244,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ///
     /// Returns `true` if an async-await specific note was added to the diagnostic.
     #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))]
-    fn maybe_note_obligation_cause_for_async_await<G: EmissionGuarantee>(
+    pub fn maybe_note_obligation_cause_for_async_await<G: EmissionGuarantee>(
         &self,
         err: &mut Diag<'_, G>,
         obligation: &PredicateObligation<'tcx>,
@@ -2712,7 +2713,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         );
     }
 
-    fn note_obligation_cause_code<G: EmissionGuarantee, T>(
+    pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
         &self,
         body_id: LocalDefId,
         err: &mut Diag<'_, G>,
@@ -3554,7 +3555,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     #[instrument(
         level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty())
     )]
-    fn suggest_await_before_try(
+    pub(super) fn suggest_await_before_try(
         &self,
         err: &mut Diag<'_>,
         obligation: &PredicateObligation<'tcx>,
@@ -3611,7 +3612,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_floating_point_literal(
+    pub(super) fn suggest_floating_point_literal(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -3635,7 +3636,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_derive(
+    pub fn suggest_derive(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -3701,7 +3702,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_dereferencing_index(
+    pub(super) fn suggest_dereferencing_index(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -4323,7 +4324,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// If the type that failed selection is an array or a reference to an array,
     /// but the trait is implemented for slices, suggest that the user converts
     /// the array into a slice.
-    fn suggest_convert_to_slice(
+    pub(super) fn suggest_convert_to_slice(
         &self,
         err: &mut Diag<'_>,
         obligation: &PredicateObligation<'tcx>,
@@ -4395,7 +4396,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn explain_hrtb_projection(
+    pub(super) fn explain_hrtb_projection(
         &self,
         diag: &mut Diag<'_>,
         pred: ty::PolyTraitPredicate<'tcx>,
@@ -4461,7 +4462,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_desugaring_async_fn_in_trait(
+    pub(super) fn suggest_desugaring_async_fn_in_trait(
         &self,
         err: &mut Diag<'_>,
         trait_ref: ty::PolyTraitRef<'tcx>,
@@ -4545,7 +4546,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         );
     }
 
-    fn ty_kind_suggestion(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option<String> {
+    pub fn ty_kind_suggestion(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Option<String> {
         let tcx = self.infcx.tcx;
         let implements_default = |ty| {
             let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
@@ -4607,7 +4612,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         })
     }
 
-    fn suggest_add_result_as_return_type(
+    pub(super) fn suggest_add_result_as_return_type(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
@@ -4648,7 +4653,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip_all)]
-    fn suggest_unsized_bound_if_applicable(
+    pub(super) fn suggest_unsized_bound_if_applicable(
         &self,
         err: &mut Diag<'_>,
         obligation: &PredicateObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index a46cba35b2d..0ee4485a365 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,11 +1,30 @@
-use crate::fluent_generated as fluent;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
-    SubdiagMessageOp, Subdiagnostic,
+    codes::*, Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
+    EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
+use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{walk_ty, Visitor};
+use rustc_hir::FnRetTy;
+use rustc_hir::GenericParamKind;
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::{self, print::PrintTraitRefExt as _, ClosureKind, PolyTraitRef, Ty};
-use rustc_span::{Span, Symbol};
+use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
+use rustc_middle::ty::{
+    self, print::PrintTraitRefExt as _, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty,
+    TyCtxt,
+};
+use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::{BytePos, Span};
+
+use crate::error_reporting::infer::need_type_info::UnderspecifiedArgKind;
+use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted;
+use crate::error_reporting::infer::ObligationCauseAsDiagArg;
+use crate::fluent_generated as fluent;
+
+use std::path::PathBuf;
+
+pub mod note_and_explain;
 
 #[derive(Diagnostic)]
 #[diag(trait_selection_dump_vtable_entries)]
@@ -170,3 +189,1613 @@ pub(crate) struct AsyncClosureNotFn {
     pub span: Span,
     pub kind: &'static str,
 }
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_type_annotations_needed, code = E0282)]
+pub struct AnnotationRequired<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+    #[note(trait_selection_full_type_written)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
+}
+
+// Copy of `AnnotationRequired` for E0283
+#[derive(Diagnostic)]
+#[diag(trait_selection_type_annotations_needed, code = E0283)]
+pub struct AmbiguousImpl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+    #[note(trait_selection_full_type_written)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
+}
+
+// Copy of `AnnotationRequired` for E0284
+#[derive(Diagnostic)]
+#[diag(trait_selection_type_annotations_needed, code = E0284)]
+pub struct AmbiguousReturn<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+    #[note(trait_selection_full_type_written)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
+}
+
+// Used when a better one isn't available
+#[derive(Subdiagnostic)]
+#[label(trait_selection_label_bad)]
+pub struct InferenceBadError<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub bad_kind: &'static str,
+    pub prefix_kind: UnderspecifiedArgKind,
+    pub has_parent: bool,
+    pub prefix: &'a str,
+    pub parent_prefix: &'a str,
+    pub parent_name: String,
+    pub name: String,
+}
+
+#[derive(Subdiagnostic)]
+pub enum SourceKindSubdiag<'a> {
+    #[suggestion(
+        trait_selection_source_kind_subdiag_let,
+        style = "verbose",
+        code = ": {type_name}",
+        applicability = "has-placeholders"
+    )]
+    LetLike {
+        #[primary_span]
+        span: Span,
+        name: String,
+        type_name: String,
+        kind: &'static str,
+        x_kind: &'static str,
+        prefix_kind: UnderspecifiedArgKind,
+        prefix: &'a str,
+        arg_name: String,
+    },
+    #[label(trait_selection_source_kind_subdiag_generic_label)]
+    GenericLabel {
+        #[primary_span]
+        span: Span,
+        is_type: bool,
+        param_name: String,
+        parent_exists: bool,
+        parent_prefix: String,
+        parent_name: String,
+    },
+    #[suggestion(
+        trait_selection_source_kind_subdiag_generic_suggestion,
+        style = "verbose",
+        code = "::<{args}>",
+        applicability = "has-placeholders"
+    )]
+    GenericSuggestion {
+        #[primary_span]
+        span: Span,
+        arg_count: usize,
+        args: String,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub enum SourceKindMultiSuggestion<'a> {
+    #[multipart_suggestion(
+        trait_selection_source_kind_fully_qualified,
+        style = "verbose",
+        applicability = "has-placeholders"
+    )]
+    FullyQualified {
+        #[suggestion_part(code = "{def_path}({adjustment}")]
+        span_lo: Span,
+        #[suggestion_part(code = "{successor_pos}")]
+        span_hi: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor_pos: &'a str,
+    },
+    #[multipart_suggestion(
+        trait_selection_source_kind_closure_return,
+        style = "verbose",
+        applicability = "has-placeholders"
+    )]
+    ClosureReturn {
+        #[suggestion_part(code = "{start_span_code}")]
+        start_span: Span,
+        start_span_code: String,
+        #[suggestion_part(code = " }}")]
+        end_span: Option<Span>,
+    },
+}
+
+impl<'a> SourceKindMultiSuggestion<'a> {
+    pub fn new_fully_qualified(
+        span: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor: (&'a str, BytePos),
+    ) -> Self {
+        Self::FullyQualified {
+            span_lo: span.shrink_to_lo(),
+            span_hi: span.shrink_to_hi().with_hi(successor.1),
+            def_path,
+            adjustment,
+            successor_pos: successor.0,
+        }
+    }
+
+    pub fn new_closure_return(
+        ty_info: String,
+        data: &'a FnRetTy<'a>,
+        should_wrap_expr: Option<Span>,
+    ) -> Self {
+        let arrow = match data {
+            FnRetTy::DefaultReturn(_) => " -> ",
+            _ => "",
+        };
+        let (start_span, start_span_code, end_span) = match should_wrap_expr {
+            Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)),
+            None => (data.span(), format!("{arrow}{ty_info}"), None),
+        };
+        Self::ClosureReturn { start_span, start_span_code, end_span }
+    }
+}
+
+pub enum RegionOriginNote<'a> {
+    Plain {
+        span: Span,
+        msg: DiagMessage,
+    },
+    WithName {
+        span: Span,
+        msg: DiagMessage,
+        name: &'a str,
+        continues: bool,
+    },
+    WithRequirement {
+        span: Span,
+        requirement: ObligationCauseAsDiagArg<'a>,
+        expected_found: Option<(DiagStyledString, DiagStyledString)>,
+    },
+}
+
+impl Subdiagnostic for RegionOriginNote<'_> {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        let mut label_or_note = |span, msg: DiagMessage| {
+            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
+            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
+            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
+            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
+                diag.span_label(span, msg);
+            } else if span_is_primary && expanded_sub_count == 0 {
+                diag.note(msg);
+            } else {
+                diag.span_note(span, msg);
+            }
+        };
+        match self {
+            RegionOriginNote::Plain { span, msg } => {
+                label_or_note(span, msg);
+            }
+            RegionOriginNote::WithName { span, msg, name, continues } => {
+                label_or_note(span, msg);
+                diag.arg("name", name);
+                diag.arg("continues", continues);
+            }
+            RegionOriginNote::WithRequirement {
+                span,
+                requirement,
+                expected_found: Some((expected, found)),
+            } => {
+                label_or_note(span, fluent::trait_selection_subtype);
+                diag.arg("requirement", requirement);
+
+                diag.note_expected_found(&"", expected, &"", found);
+            }
+            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
+                // FIXME: this really should be handled at some earlier stage. Our
+                // handling of region checking when type errors are present is
+                // *terrible*.
+                label_or_note(span, fluent::trait_selection_subtype_2);
+                diag.arg("requirement", requirement);
+            }
+        };
+    }
+}
+
+pub enum LifetimeMismatchLabels {
+    InRet {
+        param_span: Span,
+        ret_span: Span,
+        span: Span,
+        label_var1: Option<Ident>,
+    },
+    Normal {
+        hir_equal: bool,
+        ty_sup: Span,
+        ty_sub: Span,
+        span: Span,
+        sup: Option<Ident>,
+        sub: Option<Ident>,
+    },
+}
+
+impl Subdiagnostic for LifetimeMismatchLabels {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        match self {
+            LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
+                diag.span_label(param_span, fluent::trait_selection_declared_different);
+                diag.span_label(ret_span, fluent::trait_selection_nothing);
+                diag.span_label(span, fluent::trait_selection_data_returned);
+                diag.arg("label_var1_exists", label_var1.is_some());
+                diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
+            }
+            LifetimeMismatchLabels::Normal {
+                hir_equal,
+                ty_sup,
+                ty_sub,
+                span,
+                sup: label_var1,
+                sub: label_var2,
+            } => {
+                if hir_equal {
+                    diag.span_label(ty_sup, fluent::trait_selection_declared_multiple);
+                    diag.span_label(ty_sub, fluent::trait_selection_nothing);
+                    diag.span_label(span, fluent::trait_selection_data_lifetime_flow);
+                } else {
+                    diag.span_label(ty_sup, fluent::trait_selection_types_declared_different);
+                    diag.span_label(ty_sub, fluent::trait_selection_nothing);
+                    diag.span_label(span, fluent::trait_selection_data_flows);
+                    diag.arg("label_var1_exists", label_var1.is_some());
+                    diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
+                    diag.arg("label_var2_exists", label_var2.is_some());
+                    diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default());
+                }
+            }
+        }
+    }
+}
+
+pub struct AddLifetimeParamsSuggestion<'a> {
+    pub tcx: TyCtxt<'a>,
+    pub generic_param_scope: LocalDefId,
+    pub sub: Region<'a>,
+    pub ty_sup: &'a hir::Ty<'a>,
+    pub ty_sub: &'a hir::Ty<'a>,
+    pub add_note: bool,
+}
+
+impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        let mut mk_suggestion = || {
+            let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
+            else {
+                return false;
+            };
+
+            let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
+            let is_impl = matches!(&node, hir::Node::ImplItem(_));
+            let (generics, parent_generics) = match node {
+                hir::Node::Item(&hir::Item {
+                    kind: hir::ItemKind::Fn(_, ref generics, ..),
+                    ..
+                })
+                | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
+                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
+                    generics,
+                    match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
+                    {
+                        hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Trait(_, _, ref generics, ..),
+                            ..
+                        })
+                        | hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
+                            ..
+                        }) => Some(generics),
+                        _ => None,
+                    },
+                ),
+                _ => return false,
+            };
+
+            let suggestion_param_name = generics
+                .params
+                .iter()
+                .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                .map(|p| p.name.ident().name)
+                .find(|i| *i != kw::UnderscoreLifetime);
+            let introduce_new = suggestion_param_name.is_none();
+
+            let mut default = "'a".to_string();
+            if let Some(parent_generics) = parent_generics {
+                let used: FxHashSet<_> = parent_generics
+                    .params
+                    .iter()
+                    .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                    .map(|p| p.name.ident().name)
+                    .filter(|i| *i != kw::UnderscoreLifetime)
+                    .map(|l| l.to_string())
+                    .collect();
+                if let Some(lt) =
+                    ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
+                {
+                    // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
+                    // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
+                    // likely to be an over-constraining lifetime requirement, so we always add a
+                    // lifetime to the `fn`.
+                    default = lt;
+                }
+            }
+            let suggestion_param_name =
+                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
+
+            struct ImplicitLifetimeFinder {
+                suggestions: Vec<(Span, String)>,
+                suggestion_param_name: String,
+            }
+
+            impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
+                fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+                    let make_suggestion = |ident: Ident| {
+                        if ident.name == kw::Empty && ident.span.is_empty() {
+                            format!("{}, ", self.suggestion_param_name)
+                        } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
+                            format!("{} ", self.suggestion_param_name)
+                        } else {
+                            self.suggestion_param_name.clone()
+                        }
+                    };
+                    match ty.kind {
+                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
+                            for segment in path.segments {
+                                if let Some(args) = segment.args {
+                                    if args.args.iter().all(|arg| {
+                                        matches!(
+                                            arg,
+                                            hir::GenericArg::Lifetime(lifetime)
+                                            if lifetime.ident.name == kw::Empty
+                                        )
+                                    }) {
+                                        self.suggestions.push((
+                                            segment.ident.span.shrink_to_hi(),
+                                            format!(
+                                                "<{}>",
+                                                args.args
+                                                    .iter()
+                                                    .map(|_| self.suggestion_param_name.clone())
+                                                    .collect::<Vec<_>>()
+                                                    .join(", ")
+                                            ),
+                                        ));
+                                    } else {
+                                        for arg in args.args {
+                                            if let hir::GenericArg::Lifetime(lifetime) = arg
+                                                && lifetime.is_anonymous()
+                                            {
+                                                self.suggestions.push((
+                                                    lifetime.ident.span,
+                                                    make_suggestion(lifetime.ident),
+                                                ));
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
+                            self.suggestions
+                                .push((lifetime.ident.span, make_suggestion(lifetime.ident)));
+                        }
+                        _ => {}
+                    }
+                    walk_ty(self, ty);
+                }
+            }
+            let mut visitor = ImplicitLifetimeFinder {
+                suggestions: vec![],
+                suggestion_param_name: suggestion_param_name.clone(),
+            };
+            if let Some(fn_decl) = node.fn_decl()
+                && let hir::FnRetTy::Return(ty) = fn_decl.output
+            {
+                visitor.visit_ty(ty);
+            }
+            if visitor.suggestions.is_empty() {
+                // Do not suggest constraining the `&self` param, but rather the return type.
+                // If that is wrong (because it is not sufficient), a follow up error will tell the
+                // user to fix it. This way we lower the chances of *over* constraining, but still
+                // get the cake of "correctly" contrained in two steps.
+                visitor.visit_ty(self.ty_sup);
+            }
+            visitor.visit_ty(self.ty_sub);
+            if visitor.suggestions.is_empty() {
+                return false;
+            }
+            if introduce_new {
+                let new_param_suggestion = if let Some(first) =
+                    generics.params.iter().find(|p| !p.name.ident().span.is_empty())
+                {
+                    (first.span.shrink_to_lo(), format!("{suggestion_param_name}, "))
+                } else {
+                    (generics.span, format!("<{suggestion_param_name}>"))
+                };
+
+                visitor.suggestions.push(new_param_suggestion);
+            }
+            diag.multipart_suggestion_verbose(
+                fluent::trait_selection_lifetime_param_suggestion,
+                visitor.suggestions,
+                Applicability::MaybeIncorrect,
+            );
+            diag.arg("is_impl", is_impl);
+            diag.arg("is_reuse", !introduce_new);
+
+            true
+        };
+        if mk_suggestion() && self.add_note {
+            diag.note(fluent::trait_selection_lifetime_param_suggestion_elided);
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_lifetime_mismatch, code = E0623)]
+pub struct LifetimeMismatch<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub labels: LifetimeMismatchLabels,
+    #[subdiagnostic]
+    pub suggestion: AddLifetimeParamsSuggestion<'a>,
+}
+
+pub struct IntroducesStaticBecauseUnmetLifetimeReq {
+    pub unmet_requirements: MultiSpan,
+    pub binding_span: Span,
+}
+
+impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        mut self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        self.unmet_requirements
+            .push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static);
+        diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req);
+    }
+}
+
+// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
+#[derive(Subdiagnostic)]
+pub enum DoesNotOutliveStaticFromImpl {
+    #[note(trait_selection_does_not_outlive_static_from_impl)]
+    Spanned {
+        #[primary_span]
+        span: Span,
+    },
+    #[note(trait_selection_does_not_outlive_static_from_impl)]
+    Unspanned,
+}
+
+#[derive(Subdiagnostic)]
+pub enum ImplicitStaticLifetimeSubdiag {
+    #[note(trait_selection_implicit_static_lifetime_note)]
+    Note {
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion(
+        trait_selection_implicit_static_lifetime_suggestion,
+        style = "verbose",
+        code = " + '_",
+        applicability = "maybe-incorrect"
+    )]
+    Sugg {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_mismatched_static_lifetime)]
+pub struct MismatchedStaticLifetime<'a> {
+    #[primary_span]
+    pub cause_span: Span,
+    #[subdiagnostic]
+    pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
+    #[subdiagnostic]
+    pub expl: Option<note_and_explain::RegionExplanation<'a>>,
+    #[subdiagnostic]
+    pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
+    #[subdiagnostic]
+    pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
+}
+
+#[derive(Diagnostic)]
+pub enum ExplicitLifetimeRequired<'a> {
+    #[diag(trait_selection_explicit_lifetime_required_with_ident, code = E0621)]
+    WithIdent {
+        #[primary_span]
+        #[label]
+        span: Span,
+        simple_ident: Ident,
+        named: String,
+        #[suggestion(
+            trait_selection_explicit_lifetime_required_sugg_with_ident,
+            code = "{new_ty}",
+            applicability = "unspecified"
+        )]
+        new_ty_span: Span,
+        #[skip_arg]
+        new_ty: Ty<'a>,
+    },
+    #[diag(trait_selection_explicit_lifetime_required_with_param_type, code = E0621)]
+    WithParamType {
+        #[primary_span]
+        #[label]
+        span: Span,
+        named: String,
+        #[suggestion(
+            trait_selection_explicit_lifetime_required_sugg_with_param_type,
+            code = "{new_ty}",
+            applicability = "unspecified"
+        )]
+        new_ty_span: Span,
+        #[skip_arg]
+        new_ty: Ty<'a>,
+    },
+}
+
+pub enum TyOrSig<'tcx> {
+    Ty(Highlighted<'tcx, Ty<'tcx>>),
+    ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
+}
+
+impl IntoDiagArg for TyOrSig<'_> {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        match self {
+            TyOrSig::Ty(ty) => ty.into_diag_arg(),
+            TyOrSig::ClosureSig(sig) => sig.into_diag_arg(),
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+pub enum ActualImplExplNotes<'tcx> {
+    #[note(trait_selection_actual_impl_expl_expected_signature_two)]
+    ExpectedSignatureTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_signature_any)]
+    ExpectedSignatureAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_signature_some)]
+    ExpectedSignatureSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_signature_nothing)]
+    ExpectedSignatureNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_passive_two)]
+    ExpectedPassiveTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_passive_any)]
+    ExpectedPassiveAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_passive_some)]
+    ExpectedPassiveSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_passive_nothing)]
+    ExpectedPassiveNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_other_two)]
+    ExpectedOtherTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_other_any)]
+    ExpectedOtherAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_other_some)]
+    ExpectedOtherSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_expected_other_nothing)]
+    ExpectedOtherNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(trait_selection_actual_impl_expl_but_actually_implements_trait)]
+    ButActuallyImplementsTrait {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+    },
+    #[note(trait_selection_actual_impl_expl_but_actually_implemented_for_ty)]
+    ButActuallyImplementedForTy {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+        ty: String,
+    },
+    #[note(trait_selection_actual_impl_expl_but_actually_ty_implements)]
+    ButActuallyTyImplements {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+        ty: String,
+    },
+}
+
+pub enum ActualImplExpectedKind {
+    Signature,
+    Passive,
+    Other,
+}
+
+pub enum ActualImplExpectedLifetimeKind {
+    Two,
+    Any,
+    Some,
+    Nothing,
+}
+
+impl<'tcx> ActualImplExplNotes<'tcx> {
+    pub fn new_expected(
+        kind: ActualImplExpectedKind,
+        lt_kind: ActualImplExpectedLifetimeKind,
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    ) -> Self {
+        match (kind, lt_kind) {
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedSignatureTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedPassiveTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedOtherTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_trait_placeholder_mismatch)]
+pub struct TraitPlaceholderMismatch<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    #[label(trait_selection_label_satisfy)]
+    pub satisfy_span: Option<Span>,
+    #[label(trait_selection_label_where)]
+    pub where_span: Option<Span>,
+    #[label(trait_selection_label_dup)]
+    pub dup_span: Option<Span>,
+    pub def_id: String,
+    pub trait_def_id: String,
+
+    #[subdiagnostic]
+    pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
+}
+
+pub struct ConsiderBorrowingParamHelp {
+    pub spans: Vec<Span>,
+}
+
+impl Subdiagnostic for ConsiderBorrowingParamHelp {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        f: &F,
+    ) {
+        let mut type_param_span: MultiSpan = self.spans.clone().into();
+        for &span in &self.spans {
+            // Seems like we can't call f() here as Into<DiagMessage> is required
+            type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing);
+        }
+        let msg = f(diag, fluent::trait_selection_tid_param_help.into());
+        diag.span_help(type_param_span, msg);
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[help(trait_selection_tid_rel_help)]
+pub struct RelationshipHelp;
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_trait_impl_diff)]
+pub struct TraitImplDiff {
+    #[primary_span]
+    #[label(trait_selection_found)]
+    pub sp: Span,
+    #[label(trait_selection_expected)]
+    pub trait_sp: Span,
+    #[note(trait_selection_expected_found)]
+    pub note: (),
+    #[subdiagnostic]
+    pub param_help: ConsiderBorrowingParamHelp,
+    #[subdiagnostic]
+    // Seems like subdiagnostics are always pushed to the end, so this one
+    // also has to be a subdiagnostic to maintain order.
+    pub rel_help: Option<RelationshipHelp>,
+    pub expected: String,
+    pub found: String,
+}
+
+pub struct DynTraitConstraintSuggestion {
+    pub span: Span,
+    pub ident: Ident,
+}
+
+impl Subdiagnostic for DynTraitConstraintSuggestion {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        f: &F,
+    ) {
+        let mut multi_span: MultiSpan = vec![self.span].into();
+        multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label);
+        multi_span
+            .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement);
+        let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into());
+        diag.span_note(multi_span, msg);
+        let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into());
+        diag.span_suggestion_verbose(
+            self.span.shrink_to_hi(),
+            msg,
+            " + '_",
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_but_calling_introduces, code = E0772)]
+pub struct ButCallingIntroduces {
+    #[label(trait_selection_label1)]
+    pub param_ty_span: Span,
+    #[primary_span]
+    #[label(trait_selection_label2)]
+    pub cause_span: Span,
+
+    pub has_param_name: bool,
+    pub param_name: String,
+    pub has_lifetime: bool,
+    pub lifetime: String,
+    pub assoc_item: Symbol,
+    pub has_impl_path: bool,
+    pub impl_path: String,
+}
+
+pub struct ReqIntroducedLocations {
+    pub span: MultiSpan,
+    pub spans: Vec<Span>,
+    pub fn_decl_span: Span,
+    pub cause_span: Span,
+    pub add_label: bool,
+}
+
+impl Subdiagnostic for ReqIntroducedLocations {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        mut self,
+        diag: &mut Diag<'_, G>,
+        f: &F,
+    ) {
+        for sp in self.spans {
+            self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here);
+        }
+
+        if self.add_label {
+            self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by);
+        }
+        self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of);
+        let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into());
+        diag.span_note(self.span, msg);
+    }
+}
+
+pub struct MoreTargeted {
+    pub ident: Symbol,
+}
+
+impl Subdiagnostic for MoreTargeted {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        diag.code(E0772);
+        diag.primary_message(fluent::trait_selection_more_targeted);
+        diag.arg("ident", self.ident);
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_but_needs_to_satisfy, code = E0759)]
+pub struct ButNeedsToSatisfy {
+    #[primary_span]
+    pub sp: Span,
+    #[label(trait_selection_influencer)]
+    pub influencer_point: Span,
+    #[label(trait_selection_used_here)]
+    pub spans: Vec<Span>,
+    #[label(trait_selection_require)]
+    pub require_span_as_label: Option<Span>,
+    #[note(trait_selection_require)]
+    pub require_span_as_note: Option<Span>,
+    #[note(trait_selection_introduced_by_bound)]
+    pub bound: Option<Span>,
+
+    #[subdiagnostic]
+    pub req_introduces_loc: Option<ReqIntroducedLocations>,
+
+    pub has_param_name: bool,
+    pub param_name: String,
+    pub spans_empty: bool,
+    pub has_lifetime: bool,
+    pub lifetime: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_outlives_content, code = E0312)]
+pub struct OutlivesContent<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_outlives_bound, code = E0476)]
+pub struct OutlivesBound<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_fulfill_req_lifetime, code = E0477)]
+pub struct FulfillReqLifetime<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'a>,
+    #[subdiagnostic]
+    pub note: Option<note_and_explain::RegionExplanation<'a>>,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_lf_bound_not_satisfied, code = E0478)]
+pub struct LfBoundNotSatisfied<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_ref_longer_than_data, code = E0491)]
+pub struct RefLongerThanData<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'a>,
+    #[subdiagnostic]
+    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum WhereClauseSuggestions {
+    #[suggestion(
+        trait_selection_where_remove,
+        code = "",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
+    Remove {
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion(
+        trait_selection_where_copy_predicates,
+        code = "{space}where {trait_predicates}",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
+    CopyPredicates {
+        #[primary_span]
+        span: Span,
+        space: &'static str,
+        trait_predicates: String,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestRemoveSemiOrReturnBinding {
+    #[multipart_suggestion(
+        trait_selection_srs_remove_and_box,
+        applicability = "machine-applicable"
+    )]
+    RemoveAndBox {
+        #[suggestion_part(code = "Box::new(")]
+        first_lo: Span,
+        #[suggestion_part(code = ")")]
+        first_hi: Span,
+        #[suggestion_part(code = "Box::new(")]
+        second_lo: Span,
+        #[suggestion_part(code = ")")]
+        second_hi: Span,
+        #[suggestion_part(code = "")]
+        sp: Span,
+    },
+    #[suggestion(
+        trait_selection_srs_remove,
+        style = "short",
+        code = "",
+        applicability = "machine-applicable"
+    )]
+    Remove {
+        #[primary_span]
+        sp: Span,
+    },
+    #[suggestion(
+        trait_selection_srs_add,
+        style = "verbose",
+        code = "{code}",
+        applicability = "maybe-incorrect"
+    )]
+    Add {
+        #[primary_span]
+        sp: Span,
+        code: String,
+        ident: Ident,
+    },
+    #[note(trait_selection_srs_add_one)]
+    AddOne {
+        #[primary_span]
+        spans: MultiSpan,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub enum ConsiderAddingAwait {
+    #[help(trait_selection_await_both_futures)]
+    BothFuturesHelp,
+    #[multipart_suggestion(trait_selection_await_both_futures, applicability = "maybe-incorrect")]
+    BothFuturesSugg {
+        #[suggestion_part(code = ".await")]
+        first: Span,
+        #[suggestion_part(code = ".await")]
+        second: Span,
+    },
+    #[suggestion(
+        trait_selection_await_future,
+        code = ".await",
+        style = "verbose",
+        applicability = "maybe-incorrect"
+    )]
+    FutureSugg {
+        #[primary_span]
+        span: Span,
+    },
+    #[note(trait_selection_await_note)]
+    FutureSuggNote {
+        #[primary_span]
+        span: Span,
+    },
+    #[multipart_suggestion(
+        trait_selection_await_future,
+        style = "verbose",
+        applicability = "maybe-incorrect"
+    )]
+    FutureSuggMultiple {
+        #[suggestion_part(code = ".await")]
+        spans: Vec<Span>,
+    },
+}
+
+#[derive(Diagnostic)]
+pub enum PlaceholderRelationLfNotSatisfied {
+    #[diag(trait_selection_lf_bound_not_satisfied)]
+    HasBoth {
+        #[primary_span]
+        span: Span,
+        #[note(trait_selection_prlf_defined_with_sub)]
+        sub_span: Span,
+        #[note(trait_selection_prlf_must_outlive_with_sup)]
+        sup_span: Span,
+        sub_symbol: Symbol,
+        sup_symbol: Symbol,
+        #[note(trait_selection_prlf_known_limitation)]
+        note: (),
+    },
+    #[diag(trait_selection_lf_bound_not_satisfied)]
+    HasSub {
+        #[primary_span]
+        span: Span,
+        #[note(trait_selection_prlf_defined_with_sub)]
+        sub_span: Span,
+        #[note(trait_selection_prlf_must_outlive_without_sup)]
+        sup_span: Span,
+        sub_symbol: Symbol,
+        #[note(trait_selection_prlf_known_limitation)]
+        note: (),
+    },
+    #[diag(trait_selection_lf_bound_not_satisfied)]
+    HasSup {
+        #[primary_span]
+        span: Span,
+        #[note(trait_selection_prlf_defined_without_sub)]
+        sub_span: Span,
+        #[note(trait_selection_prlf_must_outlive_with_sup)]
+        sup_span: Span,
+        sup_symbol: Symbol,
+        #[note(trait_selection_prlf_known_limitation)]
+        note: (),
+    },
+    #[diag(trait_selection_lf_bound_not_satisfied)]
+    HasNone {
+        #[primary_span]
+        span: Span,
+        #[note(trait_selection_prlf_defined_without_sub)]
+        sub_span: Span,
+        #[note(trait_selection_prlf_must_outlive_without_sup)]
+        sup_span: Span,
+        #[note(trait_selection_prlf_known_limitation)]
+        note: (),
+    },
+    #[diag(trait_selection_lf_bound_not_satisfied)]
+    OnlyPrimarySpan {
+        #[primary_span]
+        span: Span,
+        #[note(trait_selection_prlf_known_limitation)]
+        note: (),
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_opaque_captures_lifetime, code = E0700)]
+pub struct OpaqueCapturesLifetime<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub opaque_ty_span: Span,
+    pub opaque_ty: Ty<'tcx>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum FunctionPointerSuggestion<'a> {
+    #[suggestion(
+        trait_selection_fps_use_ref,
+        code = "&{fn_name}",
+        style = "verbose",
+        applicability = "maybe-incorrect"
+    )]
+    UseRef {
+        #[primary_span]
+        span: Span,
+        #[skip_arg]
+        fn_name: String,
+    },
+    #[suggestion(
+        trait_selection_fps_remove_ref,
+        code = "{fn_name}",
+        style = "verbose",
+        applicability = "maybe-incorrect"
+    )]
+    RemoveRef {
+        #[primary_span]
+        span: Span,
+        #[skip_arg]
+        fn_name: String,
+    },
+    #[suggestion(
+        trait_selection_fps_cast,
+        code = "&({fn_name} as {sig})",
+        style = "verbose",
+        applicability = "maybe-incorrect"
+    )]
+    CastRef {
+        #[primary_span]
+        span: Span,
+        #[skip_arg]
+        fn_name: String,
+        #[skip_arg]
+        sig: Binder<'a, FnSig<'a>>,
+    },
+    #[suggestion(
+        trait_selection_fps_cast,
+        code = "{fn_name} as {sig}",
+        style = "verbose",
+        applicability = "maybe-incorrect"
+    )]
+    Cast {
+        #[primary_span]
+        span: Span,
+        #[skip_arg]
+        fn_name: String,
+        #[skip_arg]
+        sig: Binder<'a, FnSig<'a>>,
+    },
+    #[suggestion(
+        trait_selection_fps_cast_both,
+        code = "{fn_name} as {found_sig}",
+        style = "hidden",
+        applicability = "maybe-incorrect"
+    )]
+    CastBoth {
+        #[primary_span]
+        span: Span,
+        #[skip_arg]
+        fn_name: String,
+        #[skip_arg]
+        found_sig: Binder<'a, FnSig<'a>>,
+        expected_sig: Binder<'a, FnSig<'a>>,
+    },
+    #[suggestion(
+        trait_selection_fps_cast_both,
+        code = "&({fn_name} as {found_sig})",
+        style = "hidden",
+        applicability = "maybe-incorrect"
+    )]
+    CastBothRef {
+        #[primary_span]
+        span: Span,
+        #[skip_arg]
+        fn_name: String,
+        #[skip_arg]
+        found_sig: Binder<'a, FnSig<'a>>,
+        expected_sig: Binder<'a, FnSig<'a>>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[note(trait_selection_fps_items_are_distinct)]
+pub struct FnItemsAreDistinct;
+
+#[derive(Subdiagnostic)]
+#[note(trait_selection_fn_uniq_types)]
+pub struct FnUniqTypes;
+
+#[derive(Subdiagnostic)]
+#[help(trait_selection_fn_consider_casting)]
+pub struct FnConsiderCasting {
+    pub casting: String,
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestAccessingField<'a> {
+    #[suggestion(
+        trait_selection_suggest_accessing_field,
+        code = "{snippet}.{name}",
+        applicability = "maybe-incorrect"
+    )]
+    Safe {
+        #[primary_span]
+        span: Span,
+        snippet: String,
+        name: Symbol,
+        ty: Ty<'a>,
+    },
+    #[suggestion(
+        trait_selection_suggest_accessing_field,
+        code = "unsafe {{ {snippet}.{name} }}",
+        applicability = "maybe-incorrect"
+    )]
+    Unsafe {
+        #[primary_span]
+        span: Span,
+        snippet: String,
+        name: Symbol,
+        ty: Ty<'a>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(trait_selection_stp_wrap_one, applicability = "maybe-incorrect")]
+pub struct SuggestTuplePatternOne {
+    pub variant: String,
+    #[suggestion_part(code = "{variant}(")]
+    pub span_low: Span,
+    #[suggestion_part(code = ")")]
+    pub span_high: Span,
+}
+
+pub struct SuggestTuplePatternMany {
+    pub path: String,
+    pub cause_span: Span,
+    pub compatible_variants: Vec<String>,
+}
+
+impl Subdiagnostic for SuggestTuplePatternMany {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        f: &F,
+    ) {
+        diag.arg("path", self.path);
+        let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into());
+        diag.multipart_suggestions(
+            message,
+            self.compatible_variants.into_iter().map(|variant| {
+                vec![
+                    (self.cause_span.shrink_to_lo(), format!("{variant}(")),
+                    (self.cause_span.shrink_to_hi(), ")".to_string()),
+                ]
+            }),
+            rustc_errors::Applicability::MaybeIncorrect,
+        );
+    }
+}
+
+#[derive(Subdiagnostic)]
+pub enum TypeErrorAdditionalDiags {
+    #[suggestion(
+        trait_selection_meant_byte_literal,
+        code = "b'{code}'",
+        applicability = "machine-applicable"
+    )]
+    MeantByteLiteral {
+        #[primary_span]
+        span: Span,
+        code: String,
+    },
+    #[suggestion(
+        trait_selection_meant_char_literal,
+        code = "'{code}'",
+        applicability = "machine-applicable"
+    )]
+    MeantCharLiteral {
+        #[primary_span]
+        span: Span,
+        code: String,
+    },
+    #[multipart_suggestion(
+        trait_selection_meant_str_literal,
+        applicability = "machine-applicable"
+    )]
+    MeantStrLiteral {
+        #[suggestion_part(code = "\"")]
+        start: Span,
+        #[suggestion_part(code = "\"")]
+        end: Span,
+    },
+    #[suggestion(
+        trait_selection_consider_specifying_length,
+        code = "{length}",
+        applicability = "maybe-incorrect"
+    )]
+    ConsiderSpecifyingLength {
+        #[primary_span]
+        span: Span,
+        length: u64,
+    },
+    #[note(trait_selection_try_cannot_convert)]
+    TryCannotConvert { found: String, expected: String },
+    #[suggestion(
+        trait_selection_tuple_trailing_comma,
+        code = ",",
+        applicability = "machine-applicable"
+    )]
+    TupleOnlyComma {
+        #[primary_span]
+        span: Span,
+    },
+    #[multipart_suggestion(
+        trait_selection_tuple_trailing_comma,
+        applicability = "machine-applicable"
+    )]
+    TupleAlsoParentheses {
+        #[suggestion_part(code = "(")]
+        span_low: Span,
+        #[suggestion_part(code = ",)")]
+        span_high: Span,
+    },
+    #[suggestion(
+        trait_selection_suggest_add_let_for_letchains,
+        style = "verbose",
+        applicability = "machine-applicable",
+        code = "let "
+    )]
+    AddLetForLetChains {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+pub enum ObligationCauseFailureCode {
+    #[diag(trait_selection_oc_method_compat, code = E0308)]
+    MethodCompat {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_type_compat, code = E0308)]
+    TypeCompat {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_const_compat, code = E0308)]
+    ConstCompat {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_try_compat, code = E0308)]
+    TryCompat {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_match_compat, code = E0308)]
+    MatchCompat {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_if_else_different, code = E0308)]
+    IfElseDifferent {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_no_else, code = E0317)]
+    NoElse {
+        #[primary_span]
+        span: Span,
+    },
+    #[diag(trait_selection_oc_no_diverge, code = E0308)]
+    NoDiverge {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_fn_main_correct_type, code = E0580)]
+    FnMainCorrectType {
+        #[primary_span]
+        span: Span,
+    },
+    #[diag(trait_selection_oc_fn_start_correct_type, code = E0308)]
+    FnStartCorrectType {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
+    FnLangCorrectType {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+        lang_item_name: Symbol,
+    },
+    #[diag(trait_selection_oc_intrinsic_correct_type, code = E0308)]
+    IntrinsicCorrectType {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_method_correct_type, code = E0308)]
+    MethodCorrectType {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_closure_selfref, code = E0644)]
+    ClosureSelfref {
+        #[primary_span]
+        span: Span,
+    },
+    #[diag(trait_selection_oc_cant_coerce, code = E0308)]
+    CantCoerce {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_generic, code = E0308)]
+    Generic {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub enum AddPreciseCapturing {
+    #[suggestion(
+        trait_selection_precise_capturing_new,
+        style = "verbose",
+        code = " + use<{concatenated_bounds}>",
+        applicability = "machine-applicable"
+    )]
+    New {
+        #[primary_span]
+        span: Span,
+        new_lifetime: Symbol,
+        concatenated_bounds: String,
+    },
+    #[suggestion(
+        trait_selection_precise_capturing_existing,
+        style = "verbose",
+        code = "{pre}{new_lifetime}{post}",
+        applicability = "machine-applicable"
+    )]
+    Existing {
+        #[primary_span]
+        span: Span,
+        new_lifetime: Symbol,
+        pre: &'static str,
+        post: &'static str,
+    },
+}
+
+pub struct AddPreciseCapturingAndParams {
+    pub suggs: Vec<(Span, String)>,
+    pub new_lifetime: Symbol,
+    pub apit_spans: Vec<Span>,
+}
+
+impl Subdiagnostic for AddPreciseCapturingAndParams {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        diag.arg("new_lifetime", self.new_lifetime);
+        diag.multipart_suggestion_verbose(
+            fluent::trait_selection_precise_capturing_new_but_apit,
+            self.suggs,
+            Applicability::MaybeIncorrect,
+        );
+        diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params);
+    }
+}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
index d71b7f3c264..1f18cd8c8d8 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
@@ -173,7 +173,7 @@ impl Subdiagnostic for RegionExplanation<'_> {
         diag.arg("desc_kind", self.desc.kind);
         diag.arg("desc_arg", self.desc.arg);
 
-        let msg = f(diag, fluent::infer_region_explanation.into());
+        let msg = f(diag, fluent::trait_selection_region_explanation.into());
         if let Some(span) = self.desc.span {
             diag.span_note(span, msg);
         } else {
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index d0a12d73941..1bd66266936 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -22,11 +22,14 @@
 #![feature(control_flow_enum)]
 #![feature(extract_if)]
 #![feature(if_let_guard)]
+#![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
 #![feature(rustdoc_internals)]
+#![feature(try_blocks)]
 #![feature(type_alias_impl_trait)]
 #![feature(unwrap_infallible)]
+#![feature(yeet_expr)]
 #![recursion_limit = "512"] // For rustdoc
 // tidy-alphabetical-end
 
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index ca313590265..ddaef7c159f 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -1,7 +1,8 @@
 use std::fmt::Debug;
 use std::marker::PhantomData;
 
-use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtOverflowExt};
+use crate::error_reporting::traits::OverflowCause;
+use crate::error_reporting::InferCtxtErrorExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
 use rustc_data_structures::stack::ensure_sufficient_stack;
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index bdc27e734f9..49730b532a3 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -3,7 +3,7 @@ use std::fmt::Debug;
 
 use super::{FromSolverError, TraitEngine};
 use super::{FulfillmentContext, ScrubbedTraitError};
-use crate::error_reporting::traits::TypeErrCtxtExt;
+use crate::error_reporting::InferCtxtErrorExt;
 use crate::regions::InferCtxtRegionExt;
 use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
 use crate::solve::NextSolverError;
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 5597c8be592..cc0bb7a60b2 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,4 +1,3 @@
-use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
 use crate::infer::{InferCtxt, TyOrConstInferVar};
 use crate::traits::normalize::normalize_with_depth_to;
 use rustc_data_structures::captures::Captures;
@@ -25,6 +24,7 @@ use super::Unimplemented;
 use super::{const_evaluatable, ScrubbedTraitError};
 use super::{FulfillmentError, FulfillmentErrorCode};
 
+use crate::error_reporting::InferCtxtErrorExt;
 use crate::traits::project::PolyProjectionObligation;
 use crate::traits::project::ProjectionCacheKeyExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index baec2268629..d749b686803 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -4,6 +4,7 @@ use crate::regions::InferCtxtRegionExt;
 use crate::traits::{self, FulfillmentError, ObligationCause};
 
 use hir::LangItem;
+use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -19,6 +20,8 @@ pub enum CopyImplementationError<'tcx> {
 }
 
 pub enum ConstParamTyImplementationError<'tcx> {
+    UnsizedConstParamsFeatureRequired,
+    InvalidInnerTyOfBuiltinTy(Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
     InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
     NotAnAdtOrBuiltinAllowed,
 }
@@ -77,9 +80,9 @@ pub fn type_allowed_to_implement_copy<'tcx>(
     Ok(())
 }
 
-/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`.
+/// Checks that the fields of the type (an ADT) all implement `(Unsized?)ConstParamTy`.
 ///
-/// If fields don't implement `ConstParamTy`, return an error containing a list of
+/// If fields don't implement `(Unsized?)ConstParamTy`, return an error containing a list of
 /// those violating fields.
 ///
 /// If it's not an ADT, int ty, `bool` or `char`, returns `Err(NotAnAdtOrBuiltinAllowed)`.
@@ -87,35 +90,95 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
+    lang_item: LangItem,
     parent_cause: ObligationCause<'tcx>,
 ) -> Result<(), ConstParamTyImplementationError<'tcx>> {
-    let (adt, args) = match self_type.kind() {
-        // `core` provides these impls.
-        ty::Uint(_)
-        | ty::Int(_)
-        | ty::Bool
-        | ty::Char
-        | ty::Str
-        | ty::Array(..)
-        | ty::Slice(_)
-        | ty::Ref(.., hir::Mutability::Not)
-        | ty::Tuple(_) => return Ok(()),
+    assert!(matches!(lang_item, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy));
 
-        &ty::Adt(adt, args) => (adt, args),
+    let inner_tys: Vec<_> = match *self_type.kind() {
+        // Trivially okay as these types are all:
+        // - Sized
+        // - Contain no nested types
+        // - Have structural equality
+        ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()),
+
+        // Handle types gated under `feature(unsized_const_params)`
+        // FIXME(unsized_const_params): Make `const N: [u8]` work then forbid references
+        ty::Slice(inner_ty) | ty::Ref(_, inner_ty, Mutability::Not)
+            if lang_item == LangItem::UnsizedConstParamTy =>
+        {
+            vec![inner_ty]
+        }
+        ty::Str if lang_item == LangItem::UnsizedConstParamTy => {
+            vec![Ty::new_slice(tcx, tcx.types.u8)]
+        }
+        ty::Str | ty::Slice(..) | ty::Ref(_, _, Mutability::Not) => {
+            return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired);
+        }
+
+        ty::Array(inner_ty, _) => vec![inner_ty],
+
+        // `str` morally acts like a newtype around `[u8]`
+        ty::Tuple(inner_tys) => inner_tys.into_iter().collect(),
+
+        ty::Adt(adt, args) if adt.is_enum() || adt.is_struct() => {
+            all_fields_implement_trait(
+                tcx,
+                param_env,
+                self_type,
+                adt,
+                args,
+                parent_cause.clone(),
+                lang_item,
+            )
+            .map_err(ConstParamTyImplementationError::InfrigingFields)?;
+
+            vec![]
+        }
 
         _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
     };
 
-    all_fields_implement_trait(
-        tcx,
-        param_env,
-        self_type,
-        adt,
-        args,
-        parent_cause,
-        hir::LangItem::ConstParamTy,
-    )
-    .map_err(ConstParamTyImplementationError::InfrigingFields)?;
+    let mut infringing_inner_tys = vec![];
+    for inner_ty in inner_tys {
+        // We use an ocx per inner ty for better diagnostics
+        let infcx = tcx.infer_ctxt().build();
+        let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
+
+        ocx.register_bound(
+            parent_cause.clone(),
+            param_env,
+            inner_ty,
+            tcx.require_lang_item(lang_item, Some(parent_cause.span)),
+        );
+
+        let errors = ocx.select_all_or_error();
+        if !errors.is_empty() {
+            infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Fulfill(errors)));
+            continue;
+        }
+
+        // Check regions assuming the self type of the impl is WF
+        let outlives_env = OutlivesEnvironment::with_bounds(
+            param_env,
+            infcx.implied_bounds_tys(
+                param_env,
+                parent_cause.body_id,
+                &FxIndexSet::from_iter([self_type]),
+            ),
+        );
+        let errors = infcx.resolve_regions(&outlives_env);
+        if !errors.is_empty() {
+            infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors)));
+            continue;
+        }
+    }
+
+    if !infringing_inner_tys.is_empty() {
+        return Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(
+            infringing_inner_tys,
+        ));
+    }
 
     Ok(())
 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index f7eb1730582..c57ca014799 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -22,7 +22,7 @@ mod util;
 pub mod vtable;
 pub mod wf;
 
-use crate::error_reporting::traits::TypeErrCtxtExt as _;
+use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::regions::InferCtxtRegionExt;
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 01ba8c02ea6..26cb9bb5a3d 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -3,7 +3,7 @@
 use super::SelectionContext;
 use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
 use crate::error_reporting::traits::OverflowCause;
-use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
+use crate::error_reporting::InferCtxtErrorExt;
 use crate::solve::NextSolverError;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::at::At;
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index c11e86abef8..75f1af7fcf5 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -3,7 +3,7 @@
 //! `normalize_canonicalized_projection_ty` query when it encounters projections.
 
 use crate::error_reporting::traits::OverflowCause;
-use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
+use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::at::At;
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7a93f59f163..d6590322caa 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -18,7 +18,7 @@ use super::{
     TraitQueryMode,
 };
 
-use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
+use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
 use crate::solve::InferCtxtSelectExt as _;
 use crate::traits::normalize::normalize_with_depth;
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 3ee5fd876ff..ada2c8e81de 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{
     ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
     Unimplemented,
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 2d70fdc3935..06cd6389efc 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -2,7 +2,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
-use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::{
     normalize::NormalizationResult, CanonicalAliasGoal, NoSolution,
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index f299aa0124d..405430377e5 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -704,7 +704,7 @@ impl<T> Box<[T]> {
     }
 
     /// Constructs a new boxed slice with uninitialized contents. Returns an error if
-    /// the allocation fails
+    /// the allocation fails.
     ///
     /// # Examples
     ///
@@ -739,7 +739,7 @@ impl<T> Box<[T]> {
     }
 
     /// Constructs a new boxed slice with uninitialized contents, with the memory
-    /// being filled with `0` bytes. Returns an error if the allocation fails
+    /// being filled with `0` bytes. Returns an error if the allocation fails.
     ///
     /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage
     /// of this method.
@@ -831,6 +831,85 @@ impl<T, A: Allocator> Box<[T], A> {
     pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
         unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) }
     }
+
+    /// Constructs a new boxed slice with uninitialized contents in the provided allocator. Returns an error if
+    /// the allocation fails.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api, new_uninit)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// let mut values = Box::<[u32], _>::try_new_uninit_slice_in(3, System)?;
+    /// let values = unsafe {
+    ///     // Deferred initialization:
+    ///     values[0].as_mut_ptr().write(1);
+    ///     values[1].as_mut_ptr().write(2);
+    ///     values[2].as_mut_ptr().write(3);
+    ///     values.assume_init()
+    /// };
+    ///
+    /// assert_eq!(*values, [1, 2, 3]);
+    /// # Ok::<(), std::alloc::AllocError>(())
+    /// ```
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[inline]
+    pub fn try_new_uninit_slice_in(
+        len: usize,
+        alloc: A,
+    ) -> Result<Box<[mem::MaybeUninit<T>], A>, AllocError> {
+        let ptr = if T::IS_ZST || len == 0 {
+            NonNull::dangling()
+        } else {
+            let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
+                Ok(l) => l,
+                Err(_) => return Err(AllocError),
+            };
+            alloc.allocate(layout)?.cast()
+        };
+        unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) }
+    }
+
+    /// Constructs a new boxed slice with uninitialized contents in the provided allocator, with the memory
+    /// being filled with `0` bytes. Returns an error if the allocation fails.
+    ///
+    /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage
+    /// of this method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api, new_uninit)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// let values = Box::<[u32], _>::try_new_zeroed_slice_in(3, System)?;
+    /// let values = unsafe { values.assume_init() };
+    ///
+    /// assert_eq!(*values, [0, 0, 0]);
+    /// # Ok::<(), std::alloc::AllocError>(())
+    /// ```
+    ///
+    /// [zeroed]: mem::MaybeUninit::zeroed
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[inline]
+    pub fn try_new_zeroed_slice_in(
+        len: usize,
+        alloc: A,
+    ) -> Result<Box<[mem::MaybeUninit<T>], A>, AllocError> {
+        let ptr = if T::IS_ZST || len == 0 {
+            NonNull::dangling()
+        } else {
+            let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
+                Ok(l) => l,
+                Err(_) => return Err(AllocError),
+            };
+            alloc.allocate_zeroed(layout)?.cast()
+        };
+        unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) }
+    }
 }
 
 impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 49f89e70255..0ec46412e95 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -165,6 +165,7 @@
 #![feature(const_unsafecell_get_mut)]
 #![feature(const_waker)]
 #![feature(coverage_attribute)]
+#![feature(do_not_recommend)]
 #![feature(duration_consts_float)]
 #![feature(internal_impls_macro)]
 #![feature(ip)]
@@ -248,6 +249,7 @@
 #![feature(transparent_unions)]
 #![feature(try_blocks)]
 #![feature(unboxed_closures)]
+#![feature(unsized_const_params)]
 #![feature(unsized_fn_params)]
 #![feature(with_negative_coherence)]
 // tidy-alphabetical-end
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 21abd7c036b..a87528033c0 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -975,31 +975,73 @@ pub trait PointerLike {}
 /// that all fields are also `ConstParamTy`, which implies that recursively, all fields
 /// are `StructuralPartialEq`.
 #[lang = "const_param_ty"]
-#[unstable(feature = "adt_const_params", issue = "95174")]
+#[unstable(feature = "unsized_const_params", issue = "95174")]
 #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
 #[allow(multiple_supertrait_upcastable)]
-pub trait ConstParamTy: StructuralPartialEq + Eq {}
+// We name this differently than the derive macro so that the `adt_const_params` can
+// be used independently of `unsized_const_params` without requiring a full path
+// to the derive macro every time it is used. This should be renamed on stabilization.
+pub trait ConstParamTy_: UnsizedConstParamTy + StructuralPartialEq + Eq {}
 
 /// Derive macro generating an impl of the trait `ConstParamTy`.
 #[rustc_builtin_macro]
+#[allow_internal_unstable(unsized_const_params)]
 #[unstable(feature = "adt_const_params", issue = "95174")]
 pub macro ConstParamTy($item:item) {
     /* compiler built-in */
 }
 
+#[cfg_attr(not(bootstrap), lang = "unsized_const_param_ty")]
+#[unstable(feature = "unsized_const_params", issue = "95174")]
+#[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
+/// A marker for types which can be used as types of `const` generic parameters.
+///
+/// Equivalent to [`ConstParamTy_`] except that this is used by
+/// the `unsized_const_params` to allow for fake unstable impls.
+pub trait UnsizedConstParamTy: StructuralPartialEq + Eq {}
+
+/// Derive macro generating an impl of the trait `ConstParamTy`.
+#[cfg(not(bootstrap))]
+#[cfg_attr(not(bootstrap), rustc_builtin_macro)]
+#[cfg_attr(not(bootstrap), allow_internal_unstable(unsized_const_params))]
+#[cfg_attr(not(bootstrap), unstable(feature = "unsized_const_params", issue = "95174"))]
+pub macro UnsizedConstParamTy($item:item) {
+    /* compiler built-in */
+}
+
 // FIXME(adt_const_params): handle `ty::FnDef`/`ty::Closure`
 marker_impls! {
     #[unstable(feature = "adt_const_params", issue = "95174")]
-    ConstParamTy for
+    ConstParamTy_ for
+        usize, u8, u16, u32, u64, u128,
+        isize, i8, i16, i32, i64, i128,
+        bool,
+        char,
+        (),
+        {T: ConstParamTy_, const N: usize} [T; N],
+}
+#[cfg(bootstrap)]
+marker_impls! {
+    #[unstable(feature = "adt_const_params", issue = "95174")]
+    ConstParamTy_ for
+        str,
+        {T: ConstParamTy_} [T],
+        {T: ConstParamTy_ + ?Sized} &T,
+}
+
+marker_impls! {
+    #[unstable(feature = "unsized_const_params", issue = "95174")]
+    UnsizedConstParamTy for
         usize, u8, u16, u32, u64, u128,
         isize, i8, i16, i32, i64, i128,
         bool,
         char,
-        str /* Technically requires `[u8]: ConstParamTy` */,
         (),
-        {T: ConstParamTy, const N: usize} [T; N],
-        {T: ConstParamTy} [T],
-        {T: ?Sized + ConstParamTy} &T,
+        {T: UnsizedConstParamTy, const N: usize} [T; N],
+
+        str,
+        {T: UnsizedConstParamTy} [T],
+        {T: UnsizedConstParamTy + ?Sized} &T,
 }
 
 /// A common trait implemented by all function pointers.
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index 827426b2358..ea73c5b80ba 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -1,4 +1,4 @@
-use crate::marker::ConstParamTy;
+use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
 
 /// Are values of a type transmutable into values of another type?
 ///
@@ -39,7 +39,9 @@ pub struct Assume {
 }
 
 #[unstable(feature = "transmutability", issue = "99571")]
-impl ConstParamTy for Assume {}
+impl ConstParamTy_ for Assume {}
+#[unstable(feature = "transmutability", issue = "99571")]
+impl UnsizedConstParamTy for Assume {}
 
 impl Assume {
     /// Do not assume that *you* have ensured any safety properties are met.
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 1a8fe1e6051..d93cb8d10e6 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2507,6 +2507,7 @@ impl<T> ops::FromResidual for Option<T> {
     }
 }
 
+#[diagnostic::do_not_recommend]
 #[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
 impl<T> ops::FromResidual<ops::Yeet<()>> for Option<T> {
     #[inline]
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index f8cdcc000c5..7f278296b7b 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1990,7 +1990,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Res
         }
     }
 }
-
+#[diagnostic::do_not_recommend]
 #[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
 impl<T, E, F: From<E>> ops::FromResidual<ops::Yeet<E>> for Result<T, F> {
     #[inline]
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 8e961d8adc3..bc376b13f64 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,8 +1,9 @@
 // See core/src/primitive_docs.rs for documentation.
 
 use crate::cmp::Ordering::{self, *};
-use crate::marker::ConstParamTy;
+use crate::marker::ConstParamTy_;
 use crate::marker::StructuralPartialEq;
+use crate::marker::UnsizedConstParamTy;
 
 // Recursive macro for implementing n-ary tuple functions and operations
 //
@@ -49,8 +50,15 @@ macro_rules! tuple_impls {
 
         maybe_tuple_doc! {
             $($T)+ @
-            #[unstable(feature = "structural_match", issue = "31434")]
-            impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+)
+            #[unstable(feature = "adt_const_params", issue = "95174")]
+            impl<$($T: ConstParamTy_),+> ConstParamTy_ for ($($T,)+)
+            {}
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[unstable(feature = "unsized_const_params", issue = "95174")]
+            impl<$($T: UnsizedConstParamTy),+> UnsizedConstParamTy for ($($T,)+)
             {}
         }
 
diff --git a/library/std/src/os/horizon/mod.rs b/library/std/src/os/horizon/mod.rs
index 326d0ae9cb9..14ce409f42c 100644
--- a/library/std/src/os/horizon/mod.rs
+++ b/library/std/src/os/horizon/mod.rs
@@ -1,5 +1,6 @@
 //! Definitions for Horizon OS
 
+#![forbid(unsafe_op_in_unsafe_fn)]
 #![stable(feature = "raw_ext", since = "1.1.0")]
 
 pub mod fs;
diff --git a/library/std/src/os/horizon/raw.rs b/library/std/src/os/horizon/raw.rs
index 929fa7db1f9..e5368ea265a 100644
--- a/library/std/src/os/horizon/raw.rs
+++ b/library/std/src/os/horizon/raw.rs
@@ -38,6 +38,7 @@ pub type time_t = libc::time_t;
 #[repr(C)]
 #[derive(Clone)]
 #[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(dead_code)] // This exists for parity with other `raw` modules, but isn't actually used.
 pub struct stat {
     #[stable(feature = "raw_ext", since = "1.1.0")]
     pub st_dev: dev_t,
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index 19b4fe22093..e75bcf74e5c 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -44,7 +44,6 @@
 //!
 //! [`BorrowedFd<'a>`]: crate::os::solid::io::BorrowedFd
 
-#![deny(unsafe_op_in_unsafe_fn)]
 #![unstable(feature = "solid_ext", issue = "none")]
 
 use crate::fmt;
diff --git a/library/std/src/os/solid/mod.rs b/library/std/src/os/solid/mod.rs
index 0bb83c73ddf..75824048e24 100644
--- a/library/std/src/os/solid/mod.rs
+++ b/library/std/src/os/solid/mod.rs
@@ -1,4 +1,5 @@
 #![stable(feature = "rust1", since = "1.0.0")]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 pub mod ffi;
 pub mod io;
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 9a7741ddda7..0b158fb63df 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -1,6 +1,6 @@
 #![allow(dead_code)]
 #![allow(missing_docs, nonstandard_style)]
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 pub mod abi;
 
diff --git a/library/std/src/sys/pal/unix/alloc.rs b/library/std/src/sys/pal/unix/alloc.rs
index eb3a57c212b..625ba5247f1 100644
--- a/library/std/src/sys/pal/unix/alloc.rs
+++ b/library/std/src/sys/pal/unix/alloc.rs
@@ -67,7 +67,7 @@ cfg_if::cfg_if! {
     ))] {
         #[inline]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-            libc::memalign(layout.align(), layout.size()) as *mut u8
+            unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 }
         }
     } else {
         #[inline]
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index b8dc1538a63..bedb06043a7 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -4,7 +4,6 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
-use crate::str;
 use crate::sys::fd::FileDesc;
 use crate::sys::pal::unix::IsMinusOne;
 use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
@@ -47,7 +46,9 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
 
     #[cfg(not(target_os = "espidf"))]
     let detail = unsafe {
-        str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
+        // We can't always expect a UTF-8 environment. When we don't get that luxury,
+        // it's better to give a low-quality error message than none at all.
+        CStr::from_ptr(libc::gai_strerror(err)).to_string_lossy()
     };
 
     #[cfg(target_os = "espidf")]
diff --git a/library/std/src/sys/pal/unix/process/process_unsupported.rs b/library/std/src/sys/pal/unix/process/process_unsupported.rs
index 33d359d3f84..90d53464c83 100644
--- a/library/std/src/sys/pal/unix/process/process_unsupported.rs
+++ b/library/std/src/sys/pal/unix/process/process_unsupported.rs
@@ -1,4 +1,3 @@
-use crate::fmt;
 use crate::io;
 use crate::num::NonZero;
 use crate::sys::pal::unix::unsupported::*;
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 0db08c1a926..6eeec48bf5e 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -87,13 +87,18 @@ mod imp {
     // out many large systems and all implementations allow returning from a
     // signal handler to work. For a more detailed explanation see the
     // comments on #26458.
+    /// SIGSEGV/SIGBUS entry point
+    /// # Safety
+    /// Rust doesn't call this, it *gets called*.
+    #[forbid(unsafe_op_in_unsafe_fn)]
     unsafe extern "C" fn signal_handler(
         signum: libc::c_int,
         info: *mut libc::siginfo_t,
         _data: *mut libc::c_void,
     ) {
         let (start, end) = GUARD.get();
-        let addr = (*info).si_addr() as usize;
+        // SAFETY: this pointer is provided by the system and will always point to a valid `siginfo_t`.
+        let addr = unsafe { (*info).si_addr().addr() };
 
         // If the faulting address is within the guard page, then we print a
         // message saying so and abort.
@@ -105,9 +110,11 @@ mod imp {
             rtabort!("stack overflow");
         } else {
             // Unregister ourselves by reverting back to the default behavior.
-            let mut action: sigaction = mem::zeroed();
+            // SAFETY: assuming all platforms define struct sigaction as "zero-initializable"
+            let mut action: sigaction = unsafe { mem::zeroed() };
             action.sa_sigaction = SIG_DFL;
-            sigaction(signum, &action, ptr::null_mut());
+            // SAFETY: pray this is a well-behaved POSIX implementation of fn sigaction
+            unsafe { sigaction(signum, &action, ptr::null_mut()) };
 
             // See comment above for why this function returns.
         }
@@ -117,32 +124,45 @@ mod imp {
     static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
     static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);
 
+    /// # Safety
+    /// Must be called only once
+    #[forbid(unsafe_op_in_unsafe_fn)]
     pub unsafe fn init() {
         PAGE_SIZE.store(os::page_size(), Ordering::Relaxed);
 
         // Always write to GUARD to ensure the TLS variable is allocated.
-        let guard = install_main_guard().unwrap_or(0..0);
+        let guard = unsafe { install_main_guard().unwrap_or(0..0) };
         GUARD.set((guard.start, guard.end));
 
-        let mut action: sigaction = mem::zeroed();
+        // SAFETY: assuming all platforms define struct sigaction as "zero-initializable"
+        let mut action: sigaction = unsafe { mem::zeroed() };
         for &signal in &[SIGSEGV, SIGBUS] {
-            sigaction(signal, ptr::null_mut(), &mut action);
+            // SAFETY: just fetches the current signal handler into action
+            unsafe { sigaction(signal, ptr::null_mut(), &mut action) };
             // Configure our signal handler if one is not already set.
             if action.sa_sigaction == SIG_DFL {
+                if !NEED_ALTSTACK.load(Ordering::Relaxed) {
+                    // haven't set up our sigaltstack yet
+                    NEED_ALTSTACK.store(true, Ordering::Release);
+                    let handler = unsafe { make_handler(true) };
+                    MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
+                    mem::forget(handler);
+                }
                 action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                 action.sa_sigaction = signal_handler as sighandler_t;
-                sigaction(signal, &action, ptr::null_mut());
-                NEED_ALTSTACK.store(true, Ordering::Relaxed);
+                // SAFETY: only overriding signals if the default is set
+                unsafe { sigaction(signal, &action, ptr::null_mut()) };
             }
         }
-
-        let handler = make_handler(true);
-        MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
-        mem::forget(handler);
     }
 
+    /// # Safety
+    /// Must be called only once
+    #[forbid(unsafe_op_in_unsafe_fn)]
     pub unsafe fn cleanup() {
-        drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed));
+        // FIXME: I probably cause more bugs than I'm worth!
+        // see https://github.com/rust-lang/rust/issues/111272
+        unsafe { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)) };
     }
 
     unsafe fn get_stack() -> libc::stack_t {
@@ -187,34 +207,48 @@ mod imp {
         libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size }
     }
 
+    /// # Safety
+    /// Mutates the alternate signal stack
+    #[forbid(unsafe_op_in_unsafe_fn)]
     pub unsafe fn make_handler(main_thread: bool) -> Handler {
-        if !NEED_ALTSTACK.load(Ordering::Relaxed) {
+        if !NEED_ALTSTACK.load(Ordering::Acquire) {
             return Handler::null();
         }
 
         if !main_thread {
             // Always write to GUARD to ensure the TLS variable is allocated.
-            let guard = current_guard().unwrap_or(0..0);
+            let guard = unsafe { current_guard() }.unwrap_or(0..0);
             GUARD.set((guard.start, guard.end));
         }
 
-        let mut stack = mem::zeroed();
-        sigaltstack(ptr::null(), &mut stack);
+        // SAFETY: assuming stack_t is zero-initializable
+        let mut stack = unsafe { mem::zeroed() };
+        // SAFETY: reads current stack_t into stack
+        unsafe { sigaltstack(ptr::null(), &mut stack) };
         // Configure alternate signal stack, if one is not already set.
         if stack.ss_flags & SS_DISABLE != 0 {
-            stack = get_stack();
-            sigaltstack(&stack, ptr::null_mut());
+            // SAFETY: We warned our caller this would happen!
+            unsafe {
+                stack = get_stack();
+                sigaltstack(&stack, ptr::null_mut());
+            }
             Handler { data: stack.ss_sp as *mut libc::c_void }
         } else {
             Handler::null()
         }
     }
 
+    /// # Safety
+    /// Must be called
+    /// - only with our handler or nullptr
+    /// - only when done with our altstack
+    /// This disables the alternate signal stack!
+    #[forbid(unsafe_op_in_unsafe_fn)]
     pub unsafe fn drop_handler(data: *mut libc::c_void) {
         if !data.is_null() {
             let sigstack_size = sigstack_size();
             let page_size = PAGE_SIZE.load(Ordering::Relaxed);
-            let stack = libc::stack_t {
+            let disabling_stack = libc::stack_t {
                 ss_sp: ptr::null_mut(),
                 ss_flags: SS_DISABLE,
                 // Workaround for bug in macOS implementation of sigaltstack
@@ -223,10 +257,11 @@ mod imp {
                 // both ss_sp and ss_size should be ignored in this case.
                 ss_size: sigstack_size,
             };
-            sigaltstack(&stack, ptr::null_mut());
-            // We know from `get_stackp` that the alternate stack we installed is part of a mapping
-            // that started one page earlier, so walk back a page and unmap from there.
-            munmap(data.sub(page_size), sigstack_size + page_size);
+            // SAFETY: we warned the caller this disables the alternate signal stack!
+            unsafe { sigaltstack(&disabling_stack, ptr::null_mut()) };
+            // SAFETY: We know from `get_stackp` that the alternate stack we installed is part of
+            // a mapping that started one page earlier, so walk back a page and unmap from there.
+            unsafe { munmap(data.sub(page_size), sigstack_size + page_size) };
         }
     }
 
@@ -455,6 +490,7 @@ mod imp {
     }
 
     #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
+    // FIXME: I am probably not unsafe.
     unsafe fn current_guard() -> Option<Range<usize>> {
         let stackptr = get_stack_start()?;
         let stackaddr = stackptr.addr();
@@ -469,6 +505,7 @@ mod imp {
         target_os = "netbsd",
         target_os = "l4re"
     ))]
+    // FIXME: I am probably not unsafe.
     unsafe fn current_guard() -> Option<Range<usize>> {
         let mut ret = None;
         let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 296d19a926d..84f3d6a5399 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -8,7 +8,7 @@
 
 use crate::ffi::CStr;
 use crate::mem;
-use crate::os::raw::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void};
+use crate::os::raw::{c_uint, c_ulong, c_ushort, c_void};
 use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
 use crate::ptr;
 
@@ -19,12 +19,6 @@ pub use windows_sys::*;
 
 pub type WCHAR = u16;
 
-pub type socklen_t = c_int;
-pub type ADDRESS_FAMILY = c_ushort;
-pub use FD_SET as fd_set;
-pub use LINGER as linger;
-pub use TIMEVAL as timeval;
-
 pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _);
 
 // https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170
@@ -42,20 +36,6 @@ pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() };
 pub const OBJ_DONT_REPARSE: u32 = windows_sys::OBJ_DONT_REPARSE as u32;
 pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: u32 =
     windows_sys::FRS_ERR_SYSVOL_POPULATE_TIMEOUT as u32;
-pub const AF_INET: c_int = windows_sys::AF_INET as c_int;
-pub const AF_INET6: c_int = windows_sys::AF_INET6 as c_int;
-
-#[repr(C)]
-pub struct ip_mreq {
-    pub imr_multiaddr: in_addr,
-    pub imr_interface: in_addr,
-}
-
-#[repr(C)]
-pub struct ipv6_mreq {
-    pub ipv6mr_multiaddr: in6_addr,
-    pub ipv6mr_interface: c_uint,
-}
 
 // Equivalent to the `NT_SUCCESS` C preprocessor macro.
 // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
@@ -127,45 +107,6 @@ pub struct MOUNT_POINT_REPARSE_BUFFER {
     pub PathBuffer: WCHAR,
 }
 
-#[repr(C)]
-pub struct SOCKADDR_STORAGE_LH {
-    pub ss_family: ADDRESS_FAMILY,
-    pub __ss_pad1: [c_char; 6],
-    pub __ss_align: i64,
-    pub __ss_pad2: [c_char; 112],
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct sockaddr_in {
-    pub sin_family: ADDRESS_FAMILY,
-    pub sin_port: c_ushort,
-    pub sin_addr: in_addr,
-    pub sin_zero: [c_char; 8],
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct sockaddr_in6 {
-    pub sin6_family: ADDRESS_FAMILY,
-    pub sin6_port: c_ushort,
-    pub sin6_flowinfo: c_ulong,
-    pub sin6_addr: in6_addr,
-    pub sin6_scope_id: c_ulong,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct in_addr {
-    pub s_addr: u32,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct in6_addr {
-    pub s6_addr: [u8; 16],
-}
-
 // Desktop specific functions & types
 cfg_if::cfg_if! {
 if #[cfg(not(target_vendor = "uwp"))] {
@@ -205,42 +146,6 @@ pub unsafe extern "system" fn ReadFileEx(
     )
 }
 
-// POSIX compatibility shims.
-pub unsafe fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int {
-    windows_sys::recv(socket, buf.cast::<u8>(), len, flags)
-}
-pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int {
-    windows_sys::send(socket, buf.cast::<u8>(), len, flags)
-}
-pub unsafe fn recvfrom(
-    socket: SOCKET,
-    buf: *mut c_void,
-    len: c_int,
-    flags: c_int,
-    addr: *mut SOCKADDR,
-    addrlen: *mut c_int,
-) -> c_int {
-    windows_sys::recvfrom(socket, buf.cast::<u8>(), len, flags, addr, addrlen)
-}
-pub unsafe fn sendto(
-    socket: SOCKET,
-    buf: *const c_void,
-    len: c_int,
-    flags: c_int,
-    addr: *const SOCKADDR,
-    addrlen: c_int,
-) -> c_int {
-    windows_sys::sendto(socket, buf.cast::<u8>(), len, flags, addr, addrlen)
-}
-pub unsafe fn getaddrinfo(
-    node: *const c_char,
-    service: *const c_char,
-    hints: *const ADDRINFOA,
-    res: *mut *mut ADDRINFOA,
-) -> c_int {
-    windows_sys::getaddrinfo(node.cast::<u8>(), service.cast::<u8>(), hints, res)
-}
-
 cfg_if::cfg_if! {
 if #[cfg(not(target_vendor = "uwp"))] {
 pub unsafe fn NtReadFile(
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index 5ad4a3731d8..794e2c90c52 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2059,6 +2059,7 @@ Windows.Win32.Networking.WinSock.SOCK_RDM
 Windows.Win32.Networking.WinSock.SOCK_SEQPACKET
 Windows.Win32.Networking.WinSock.SOCK_STREAM
 Windows.Win32.Networking.WinSock.SOCKADDR
+Windows.Win32.Networking.WinSock.SOCKADDR_STORAGE
 Windows.Win32.Networking.WinSock.SOCKADDR_UN
 Windows.Win32.Networking.WinSock.SOCKET
 Windows.Win32.Networking.WinSock.SOCKET_ERROR
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index fea00fec9ae..eae0f775860 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -2890,6 +2890,14 @@ pub struct SOCKADDR {
 }
 #[repr(C)]
 #[derive(Clone, Copy)]
+pub struct SOCKADDR_STORAGE {
+    pub ss_family: ADDRESS_FAMILY,
+    pub __ss_pad1: [i8; 6],
+    pub __ss_align: i64,
+    pub __ss_pad2: [i8; 112],
+}
+#[repr(C)]
+#[derive(Clone, Copy)]
 pub struct SOCKADDR_UN {
     pub sun_family: ADDRESS_FAMILY,
     pub sun_path: [i8; 108],
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs
index d51fb56238f..b7ecff032e4 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/pal/windows/net.rs
@@ -17,14 +17,100 @@ use crate::time::Duration;
 
 use core::ffi::{c_int, c_long, c_ulong, c_ushort};
 
+#[allow(non_camel_case_types)]
 pub type wrlen_t = i32;
 
 pub mod netc {
-    pub use crate::sys::c::ADDRESS_FAMILY as sa_family_t;
-    pub use crate::sys::c::ADDRINFOA as addrinfo;
-    pub use crate::sys::c::SOCKADDR as sockaddr;
-    pub use crate::sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage;
-    pub use crate::sys::c::*;
+    //! BSD socket compatibility shim
+    //!
+    //! Some Windows API types are not quite what's expected by our cross-platform
+    //! net code. E.g. naming differences or different pointer types.
+    use crate::sys::c::{self, ADDRESS_FAMILY, ADDRINFOA, SOCKADDR, SOCKET};
+    use core::ffi::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void};
+
+    // re-exports from Windows API bindings.
+    pub use crate::sys::c::{
+        bind, connect, freeaddrinfo, getpeername, getsockname, getsockopt, listen, setsockopt,
+        ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IPPROTO_IP, IPPROTO_IPV6,
+        IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY,
+        IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL,
+        SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, SOCK_DGRAM, SOCK_STREAM,
+        SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO,
+    };
+
+    #[allow(non_camel_case_types)]
+    pub type socklen_t = c_int;
+
+    pub const AF_INET: i32 = c::AF_INET as i32;
+    pub const AF_INET6: i32 = c::AF_INET6 as i32;
+
+    // The following two structs use a union in the generated bindings but
+    // our cross-platform code expects a normal field so it's redefined here.
+    // As a consequence, we also need to redefine other structs that use this struct.
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct in_addr {
+        pub s_addr: u32,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct in6_addr {
+        pub s6_addr: [u8; 16],
+    }
+
+    #[repr(C)]
+    pub struct ip_mreq {
+        pub imr_multiaddr: in_addr,
+        pub imr_interface: in_addr,
+    }
+
+    #[repr(C)]
+    pub struct ipv6_mreq {
+        pub ipv6mr_multiaddr: in6_addr,
+        pub ipv6mr_interface: c_uint,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in {
+        pub sin_family: ADDRESS_FAMILY,
+        pub sin_port: c_ushort,
+        pub sin_addr: in_addr,
+        pub sin_zero: [c_char; 8],
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in6 {
+        pub sin6_family: ADDRESS_FAMILY,
+        pub sin6_port: c_ushort,
+        pub sin6_flowinfo: c_ulong,
+        pub sin6_addr: in6_addr,
+        pub sin6_scope_id: c_ulong,
+    }
+
+    pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int {
+        unsafe { c::send(socket, buf.cast::<u8>(), len, flags) }
+    }
+    pub unsafe fn sendto(
+        socket: SOCKET,
+        buf: *const c_void,
+        len: c_int,
+        flags: c_int,
+        addr: *const SOCKADDR,
+        addrlen: c_int,
+    ) -> c_int {
+        unsafe { c::sendto(socket, buf.cast::<u8>(), len, flags, addr, addrlen) }
+    }
+    pub unsafe fn getaddrinfo(
+        node: *const c_char,
+        service: *const c_char,
+        hints: *const ADDRINFOA,
+        res: *mut *mut ADDRINFOA,
+    ) -> c_int {
+        unsafe { c::getaddrinfo(node.cast::<u8>(), service.cast::<u8>(), hints, res) }
+    }
 }
 
 pub struct Socket(OwnedSocket);
@@ -102,8 +188,8 @@ where
 impl Socket {
     pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
         let family = match *addr {
-            SocketAddr::V4(..) => c::AF_INET,
-            SocketAddr::V6(..) => c::AF_INET6,
+            SocketAddr::V4(..) => netc::AF_INET,
+            SocketAddr::V6(..) => netc::AF_INET6,
         };
         let socket = unsafe {
             c::WSASocketW(
@@ -157,7 +243,7 @@ impl Socket {
                     return Err(io::Error::ZERO_TIMEOUT);
                 }
 
-                let mut timeout = c::timeval {
+                let mut timeout = c::TIMEVAL {
                     tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long,
                     tv_usec: timeout.subsec_micros() as c_long,
                 };
@@ -167,7 +253,7 @@ impl Socket {
                 }
 
                 let fds = {
-                    let mut fds = unsafe { mem::zeroed::<c::fd_set>() };
+                    let mut fds = unsafe { mem::zeroed::<c::FD_SET>() };
                     fds.fd_count = 1;
                     fds.fd_array[0] = self.as_raw();
                     fds
@@ -295,8 +381,8 @@ impl Socket {
         buf: &mut [u8],
         flags: c_int,
     ) -> io::Result<(usize, SocketAddr)> {
-        let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE_LH>() };
-        let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
+        let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE>() };
+        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
         let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
 
         // On unix when a socket is shut down all further reads return 0, so we
@@ -399,7 +485,7 @@ impl Socket {
     }
 
     pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
-        let linger = c::linger {
+        let linger = c::LINGER {
             l_onoff: linger.is_some() as c_ushort,
             l_linger: linger.unwrap_or_default().as_secs() as c_ushort,
         };
@@ -408,7 +494,7 @@ impl Socket {
     }
 
     pub fn linger(&self) -> io::Result<Option<Duration>> {
-        let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?;
+        let val: c::LINGER = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?;
 
         Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
     }
diff --git a/library/std/src/sys/path/unsupported_backslash.rs b/library/std/src/sys/path/unsupported_backslash.rs
index 7045c9be25b..855f443678c 100644
--- a/library/std/src/sys/path/unsupported_backslash.rs
+++ b/library/std/src/sys/path/unsupported_backslash.rs
@@ -1,3 +1,4 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
 use crate::ffi::OsStr;
 use crate::io;
 use crate::path::{Path, PathBuf, Prefix};
diff --git a/library/std/src/sys/sync/mutex/itron.rs b/library/std/src/sys/sync/mutex/itron.rs
index 4ba32a8fbcd..b29c7e1d034 100644
--- a/library/std/src/sys/sync/mutex/itron.rs
+++ b/library/std/src/sys/sync/mutex/itron.rs
@@ -1,5 +1,6 @@
 //! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and
 //! `TA_INHERIT` are available.
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::sys::pal::itron::{
     abi,
diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs
index 7558eee8edd..a8fef685ceb 100644
--- a/library/std/src/sys/sync/rwlock/solid.rs
+++ b/library/std/src/sys/sync/rwlock/solid.rs
@@ -1,4 +1,5 @@
 //! A readers-writer lock implementation backed by the SOLID kernel extension.
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::sys::pal::{
     abi,
diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs
index f6cd457046f..e08ac44e1af 100644
--- a/library/std/src/sys/thread_local/guard/windows.rs
+++ b/library/std/src/sys/thread_local/guard/windows.rs
@@ -78,19 +78,6 @@ pub fn enable() {
 pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = tls_callback;
 
 unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) {
-    // See comments above for what this is doing. Note that we don't need this
-    // trickery on GNU windows, just on MSVC.
-    #[cfg(all(target_env = "msvc", not(target_thread_local)))]
-    {
-        extern "C" {
-            static _tls_used: u8;
-        }
-
-        unsafe {
-            ptr::from_ref(&_tls_used).read_volatile();
-        }
-    }
-
     if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH {
         #[cfg(target_thread_local)]
         unsafe {
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 7e38a0996e5..9acd85cddde 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -51,6 +51,7 @@ check-aux:
 	$(Q)$(BOOTSTRAP) test --stage 2 \
 		src/tools/cargo \
 		src/tools/cargotest \
+		src/etc/test-float-parse \
 		$(BOOTSTRAP_ARGS)
 	# Run standard library tests in Miri.
 	$(Q)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 8235d4634b7..ed5b9edc86d 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -466,6 +466,7 @@ tool_check_step!(CargoMiri, "src/tools/miri/cargo-miri", SourceType::InTree);
 tool_check_step!(Rls, "src/tools/rls", SourceType::InTree);
 tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);
 tool_check_step!(MiroptTestTools, "src/tools/miropt-test-tools", SourceType::InTree);
+tool_check_step!(TestFloatParse, "src/etc/test-float-parse", SourceType::InTree);
 
 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
 
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 40a2112b192..ee7fb368a8c 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -326,4 +326,5 @@ lint_any!(
     Rustfmt, "src/tools/rustfmt", "rustfmt";
     RustInstaller, "src/tools/rust-installer", "rust-installer";
     Tidy, "src/tools/tidy", "tidy";
+    TestFloatParse, "src/etc/test-float-parse", "test-float-parse";
 );
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 1e9d2025bc7..7d67cc3b36e 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1040,6 +1040,8 @@ impl Step for PlainSourceTarball {
                 .arg(builder.src.join("./src/tools/opt-dist/Cargo.toml"))
                 .arg("--sync")
                 .arg(builder.src.join("./src/tools/rustc-perf/Cargo.toml"))
+                .arg("--sync")
+                .arg(builder.src.join("./src/tools/rustbook/Cargo.toml"))
                 // Will read the libstd Cargo.toml
                 // which uses the unstable `public-dependency` feature.
                 .env("RUSTC_BOOTSTRAP", "1")
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 633e66afe59..d8204ea00f7 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -1172,6 +1172,12 @@ impl Step for RustcBook {
     /// in the "md-doc" directory in the build output directory. Then
     /// "rustbook" is used to convert it to HTML.
     fn run(self, builder: &Builder<'_>) {
+        // These submodules are required to be checked out to build rustbook
+        // because they have Cargo dependencies that are needed.
+        #[allow(clippy::single_element_loop)] // This will change soon.
+        for path in ["src/doc/book"] {
+            builder.update_submodule(Path::new(path));
+        }
         let out_base = builder.md_doc_out(self.target).join("rustc");
         t!(fs::create_dir_all(&out_base));
         let out_listing = out_base.join("src/lints");
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 44790301841..f234b08f5e2 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -26,7 +26,6 @@ use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind};
 
 use crate::utils::exec::command;
 use build_helper::ci::CiEnv;
-use build_helper::git::get_git_merge_base;
 
 #[derive(Clone)]
 pub struct LlvmResult {
@@ -154,26 +153,18 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
 /// This retrieves the LLVM sha we *want* to use, according to git history.
 pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
     let llvm_sha = if is_git {
-        // We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we
-        // walk back further to the last bors merge commit that actually changed LLVM. The first
-        // step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD`
-        // in that case.
-        let closest_upstream = get_git_merge_base(&config.git_config(), Some(&config.src))
-            .unwrap_or_else(|_| "HEAD".into());
-        let mut rev_list = helpers::git(Some(&config.src));
-        rev_list.args(&[
-            PathBuf::from("rev-list"),
-            format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
-            "-n1".into(),
-            "--first-parent".into(),
-            closest_upstream.into(),
-            "--".into(),
-            config.src.join("src/llvm-project"),
-            config.src.join("src/bootstrap/download-ci-llvm-stamp"),
-            // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
-            config.src.join("src/version"),
-        ]);
-        output(rev_list.as_command_mut()).trim().to_owned()
+        helpers::get_closest_merge_base_commit(
+            Some(&config.src),
+            &config.git_config(),
+            &config.stage0_metadata.config.git_merge_commit_email,
+            &[
+                config.src.join("src/llvm-project"),
+                config.src.join("src/bootstrap/download-ci-llvm-stamp"),
+                // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
+                config.src.join("src/version"),
+            ],
+        )
+        .unwrap()
     } else if let Some(info) = channel::read_commit_info_file(&config.src) {
         info.sha.trim().to_owned()
     } else {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 3f0cbde64e3..cc5931c68db 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -3505,3 +3505,80 @@ impl Step for CodegenGCC {
         cargo.into_cmd().run(builder);
     }
 }
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct TestFloatParse {
+    path: PathBuf,
+    host: TargetSelection,
+}
+
+impl Step for TestFloatParse {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/etc/test-float-parse")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        for path in run.paths {
+            let path = path.assert_single_path().path.clone();
+            run.builder.ensure(Self { path, host: run.target });
+        }
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let bootstrap_host = builder.config.build;
+        let compiler = builder.compiler(0, bootstrap_host);
+        let path = self.path.to_str().unwrap();
+        let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap();
+
+        builder.ensure(compile::Std::new(compiler, self.host));
+
+        // Run any unit tests in the crate
+        let cargo_test = tool::prepare_tool_cargo(
+            builder,
+            compiler,
+            Mode::ToolStd,
+            bootstrap_host,
+            "test",
+            path,
+            SourceType::InTree,
+            &[],
+        );
+
+        run_cargo_test(
+            cargo_test,
+            &[],
+            &[],
+            crate_name,
+            crate_name,
+            compiler,
+            bootstrap_host,
+            builder,
+        );
+
+        // Run the actual parse tests.
+        let mut cargo_run = tool::prepare_tool_cargo(
+            builder,
+            compiler,
+            Mode::ToolStd,
+            bootstrap_host,
+            "run",
+            path,
+            SourceType::InTree,
+            &[],
+        );
+
+        cargo_run.arg("--");
+        if builder.config.args().is_empty() {
+            // By default, exclude tests that take longer than ~1m.
+            cargo_run.arg("--skip-huge");
+        } else {
+            cargo_run.args(builder.config.args());
+        }
+
+        cargo_run.into_cmd().run(builder);
+    }
+}
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 2f8b41334fc..087df2f8a88 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -9,7 +9,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun,
 use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
 use crate::utils::exec::{command, BootstrapCommand};
-use crate::utils::helpers::{add_dylib_path, exe, t};
+use crate::utils::helpers::{add_dylib_path, exe, get_closest_merge_base_commit, git, t};
 use crate::Compiler;
 use crate::Mode;
 use crate::{gha, Kind};
@@ -554,6 +554,57 @@ impl Step for Rustdoc {
         }
         let target = target_compiler.host;
 
+        let bin_rustdoc = || {
+            let sysroot = builder.sysroot(target_compiler);
+            let bindir = sysroot.join("bin");
+            t!(fs::create_dir_all(&bindir));
+            let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host));
+            let _ = fs::remove_file(&bin_rustdoc);
+            bin_rustdoc
+        };
+
+        // If CI rustc is enabled and we haven't modified the rustdoc sources,
+        // use the precompiled rustdoc from CI rustc's sysroot to speed up bootstrapping.
+        if builder.download_rustc()
+            && target_compiler.stage > 0
+            && builder.rust_info().is_managed_git_subrepository()
+        {
+            let commit = get_closest_merge_base_commit(
+                Some(&builder.config.src),
+                &builder.config.git_config(),
+                &builder.config.stage0_metadata.config.git_merge_commit_email,
+                &[],
+            )
+            .unwrap();
+
+            let librustdoc_src = builder.config.src.join("src/librustdoc");
+            let rustdoc_src = builder.config.src.join("src/tools/rustdoc");
+
+            // FIXME: The change detection logic here is quite similar to `Config::download_ci_rustc_commit`.
+            // It would be better to unify them.
+            let has_changes = !git(Some(&builder.config.src))
+                .allow_failure()
+                .run_always()
+                .args(["diff-index", "--quiet", &commit])
+                .arg("--")
+                .arg(librustdoc_src)
+                .arg(rustdoc_src)
+                .run(builder)
+                .is_success();
+
+            if !has_changes {
+                let precompiled_rustdoc = builder
+                    .config
+                    .ci_rustc_dir()
+                    .join("bin")
+                    .join(exe("rustdoc", target_compiler.host));
+
+                let bin_rustdoc = bin_rustdoc();
+                builder.copy_link(&precompiled_rustdoc, &bin_rustdoc);
+                return bin_rustdoc;
+            }
+        }
+
         let build_compiler = if builder.download_rustc() && target_compiler.stage == 1 {
             // We already have the stage 1 compiler, we don't need to cut the stage.
             builder.compiler(target_compiler.stage, builder.config.build)
@@ -614,11 +665,7 @@ impl Step for Rustdoc {
 
         // don't create a stage0-sysroot/bin directory.
         if target_compiler.stage > 0 {
-            let sysroot = builder.sysroot(target_compiler);
-            let bindir = sysroot.join("bin");
-            t!(fs::create_dir_all(&bindir));
-            let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host));
-            let _ = fs::remove_file(&bin_rustdoc);
+            let bin_rustdoc = bin_rustdoc();
             builder.copy_link(&tool_rustdoc, &bin_rustdoc);
             bin_rustdoc
         } else {
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index 62342ee4792..e6b3cb320cf 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -34,8 +34,10 @@ impl Step for Vendor {
             cmd.arg("--versioned-dirs");
         }
 
-        // cargo submodule must be present for `x vendor` to work.
-        builder.build.update_submodule(Path::new("src/tools/cargo"));
+        // These submodules must be present for `x vendor` to work.
+        for path in ["src/tools/cargo", "src/doc/book"] {
+            builder.build.update_submodule(Path::new(path));
+        }
 
         // Sync these paths by default.
         for p in [
@@ -44,6 +46,7 @@ impl Step for Vendor {
             "compiler/rustc_codegen_cranelift/Cargo.toml",
             "compiler/rustc_codegen_gcc/Cargo.toml",
             "src/bootstrap/Cargo.toml",
+            "src/tools/rustbook/Cargo.toml",
         ] {
             cmd.arg("--sync").arg(builder.src.join(p));
         }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 6d6df650b14..78fbea2e810 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -826,6 +826,7 @@ impl<'a> Builder<'a> {
                 clippy::Rustdoc,
                 clippy::Rustfmt,
                 clippy::RustInstaller,
+                clippy::TestFloatParse,
                 clippy::Tidy,
             ),
             Kind::Check | Kind::Fix => describe!(
@@ -840,6 +841,7 @@ impl<'a> Builder<'a> {
                 check::Rls,
                 check::Rustfmt,
                 check::RustAnalyzer,
+                check::TestFloatParse,
                 check::Bootstrap,
             ),
             Kind::Test => describe!(
@@ -901,6 +903,7 @@ impl<'a> Builder<'a> {
                 test::RustdocJson,
                 test::HtmlCheck,
                 test::RustInstaller,
+                test::TestFloatParse,
                 // Run bootstrap close to the end as it's unlikely to fail
                 test::Bootstrap,
                 // Run run-make last, since these won't pass without make on Windows
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index f96633b059a..9d5aa795c6c 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -20,7 +20,7 @@ use crate::core::build_steps::llvm;
 use crate::core::config::flags::{Color, Flags, Warnings};
 use crate::utils::cache::{Interned, INTERNER};
 use crate::utils::channel::{self, GitInfo};
-use crate::utils::helpers::{self, exe, output, t};
+use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
 use build_helper::exit;
 use serde::{Deserialize, Deserializer};
 use serde_derive::Deserialize;
@@ -2471,14 +2471,13 @@ impl Config {
 
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
-        let merge_base = output(
-            helpers::git(Some(&self.src))
-                .arg("rev-list")
-                .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
-                .args(["-n1", "--first-parent", "HEAD"])
-                .as_command_mut(),
-        );
-        let commit = merge_base.trim_end();
+        let commit = get_closest_merge_base_commit(
+            Some(&self.src),
+            &self.git_config(),
+            &self.stage0_metadata.config.git_merge_commit_email,
+            &[],
+        )
+        .unwrap();
         if commit.is_empty() {
             println!("ERROR: could not find commit hash for downloading rustc");
             println!("HELP: maybe your repository history is too shallow?");
@@ -2489,7 +2488,7 @@ impl Config {
 
         // Warn if there were changes to the compiler or standard library since the ancestor commit.
         let has_changes = !t!(helpers::git(Some(&self.src))
-            .args(["diff-index", "--quiet", commit])
+            .args(["diff-index", "--quiet", &commit])
             .arg("--")
             .args([self.src.join("compiler"), self.src.join("library")])
             .as_command_mut()
@@ -2565,14 +2564,13 @@ impl Config {
     ) -> Option<String> {
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
-        let merge_base = output(
-            helpers::git(Some(&self.src))
-                .arg("rev-list")
-                .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
-                .args(["-n1", "--first-parent", "HEAD"])
-                .as_command_mut(),
-        );
-        let commit = merge_base.trim_end();
+        let commit = get_closest_merge_base_commit(
+            Some(&self.src),
+            &self.git_config(),
+            &self.stage0_metadata.config.git_merge_commit_email,
+            &[],
+        )
+        .unwrap();
         if commit.is_empty() {
             println!("error: could not find commit hash for downloading components from CI");
             println!("help: maybe your repository history is too shallow?");
@@ -2583,7 +2581,7 @@ impl Config {
 
         // Warn if there were changes to the compiler or standard library since the ancestor commit.
         let mut git = helpers::git(Some(&self.src));
-        git.args(["diff-index", "--quiet", commit, "--"]);
+        git.args(["diff-index", "--quiet", &commit, "--"]);
 
         // Handle running from a directory other than the top level
         let top_level = &self.src;
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index d2910f8edc6..79bea50c626 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -439,7 +439,7 @@ impl Build {
 
             // Make sure we update these before gathering metadata so we don't get an error about missing
             // Cargo.toml files.
-            let rust_submodules = ["src/doc/book", "library/backtrace", "library/stdarch"];
+            let rust_submodules = ["library/backtrace", "library/stdarch"];
             for s in rust_submodules {
                 build.update_submodule(Path::new(s));
             }
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 3c82fa189be..690d7318f94 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -3,6 +3,7 @@
 //! Simple things like testing the various filesystem operations here and there,
 //! not a lot of interesting happenings here unfortunately.
 
+use build_helper::git::{get_git_merge_base, output_result, GitConfig};
 use build_helper::util::fail;
 use std::env;
 use std::ffi::OsStr;
@@ -202,7 +203,9 @@ pub fn target_supports_cranelift_backend(target: TargetSelection) -> bool {
             || target.contains("aarch64")
             || target.contains("s390x")
             || target.contains("riscv64gc")
-    } else if target.contains("darwin") || target.is_windows() {
+    } else if target.contains("darwin") {
+        target.contains("x86_64") || target.contains("aarch64")
+    } else if target.is_windows() {
         target.contains("x86_64")
     } else {
         false
@@ -521,3 +524,26 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
 
     git
 }
+
+/// Returns the closest commit available from upstream for the given `author` and `target_paths`.
+///
+/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD.
+pub fn get_closest_merge_base_commit(
+    source_dir: Option<&Path>,
+    config: &GitConfig<'_>,
+    author: &str,
+    target_paths: &[PathBuf],
+) -> Result<String, String> {
+    let mut git = git(source_dir).capture_stdout();
+
+    let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
+
+    git.arg(Path::new("rev-list"));
+    git.args([&format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
+
+    if !target_paths.is_empty() {
+        git.arg("--").args(target_paths);
+    }
+
+    Ok(output_result(git.as_command_mut())?.trim().to_owned())
+}
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 962484593b4..2621e9a6031 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -85,9 +85,9 @@ RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun
 COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
 RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
 
-RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-22/wasi-sdk-22.0-linux.tar.gz | \
+RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-23/wasi-sdk-23.0-x86_64-linux.tar.gz | \
   tar -xz
-ENV WASI_SDK_PATH=/tmp/wasi-sdk-22.0
+ENV WASI_SDK_PATH=/tmp/wasi-sdk-23.0-x86_64-linux
 
 COPY scripts/freebsd-toolchain.sh /tmp/
 RUN /tmp/freebsd-toolchain.sh i686
diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in
index c7b3376e2f1..d7c2d3fde5b 100644
--- a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in
+++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in
@@ -11,4 +11,4 @@
 #    pip-compile --allow-unsafe --generate-hashes reuse-requirements.in
 #
 
-reuse
+reuse>=4.0,<5.0
diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt
index b0f598f77ea..8784e18864b 100644
--- a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt
+++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt
@@ -4,6 +4,10 @@
 #
 #    pip-compile --allow-unsafe --generate-hashes reuse-requirements.in
 #
+attrs==23.2.0 \
+    --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \
+    --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
+    # via reuse
 binaryornot==0.4.4 \
     --hash=sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061 \
     --hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4
@@ -14,71 +18,91 @@ boolean-py==4.0 \
     # via
     #   license-expression
     #   reuse
-chardet==5.1.0 \
-    --hash=sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5 \
-    --hash=sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
     # via
     #   binaryornot
     #   python-debian
-jinja2==3.1.2 \
-    --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
-    --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+jinja2==3.1.4 \
+    --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
+    --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
     # via reuse
-license-expression==30.0.0 \
-    --hash=sha256:ad638292aa8493f84354909b517922cb823582c2ce2c4d880e42544a86bea8dd \
-    --hash=sha256:e95325110110eb2b7539ee7773b97a0724d5371ec563cc718c8cac0e38cc40cc
+license-expression==30.3.0 \
+    --hash=sha256:1295406f736b4f395ff069aec1cebfad53c0fcb3cf57df0f5ec58fc7b905aea5 \
+    --hash=sha256:ae0ba9a829d6909c785dc2f0131f13d10d68318e4a5f28af5ef152d6b52f9b41
     # via reuse
-markupsafe==2.1.1 \
-    --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
-    --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
-    --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
-    --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
-    --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
-    --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
-    --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
-    --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
-    --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
-    --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
-    --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
-    --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
-    --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
-    --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
-    --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
-    --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
-    --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
-    --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
-    --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
-    --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
-    --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
-    --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
-    --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
-    --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
-    --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
-    --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
-    --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
-    --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
-    --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
-    --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
-    --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
-    --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
-    --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
-    --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
-    --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
-    --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
-    --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
-    --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
-    --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
-    --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
+markupsafe==2.1.5 \
+    --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \
+    --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \
+    --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \
+    --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \
+    --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \
+    --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \
+    --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \
+    --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \
+    --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \
+    --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \
+    --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \
+    --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \
+    --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \
+    --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \
+    --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \
+    --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \
+    --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \
+    --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \
+    --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \
+    --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \
+    --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \
+    --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \
+    --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \
+    --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \
+    --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \
+    --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \
+    --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \
+    --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \
+    --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \
+    --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \
+    --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \
+    --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \
+    --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \
+    --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \
+    --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \
+    --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \
+    --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \
+    --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \
+    --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \
+    --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \
+    --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \
+    --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \
+    --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \
+    --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \
+    --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \
+    --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \
+    --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \
+    --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \
+    --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \
+    --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \
+    --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \
+    --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \
+    --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \
+    --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \
+    --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \
+    --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \
+    --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \
+    --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \
+    --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \
+    --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68
     # via jinja2
 python-debian==0.1.49 \
     --hash=sha256:880f3bc52e31599f2a9b432bd7691844286825087fccdcf2f6ffd5cd79a26f9f \
     --hash=sha256:8cf677a30dbcb4be7a99536c17e11308a827a4d22028dc59a67f6c6dd3f0f58c
     # via reuse
-reuse==1.1.0 \
-    --hash=sha256:7a054f6e372ad02d0b1b07368030fc38746b50ed45f5422a81994e7a88b52f1f \
-    --hash=sha256:b0f3fb9091ff513af04b555d14a4c529ab05f6a575ab192dd9b68244f1e0721d
+reuse==4.0.3 \
+    --hash=sha256:4f2c3e1213ec644e5febc50d8322d18982e4e1102af8a51d9493bfc2164a0eac \
+    --hash=sha256:b33e26ec1d105cfcfc2e904d103faec0d758994278feb95a4f4290a864562243
     # via -r reuse-requirements.in
-setuptools==66.0.0 \
-    --hash=sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab \
-    --hash=sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6
+tomlkit==0.13.0 \
+    --hash=sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72 \
+    --hash=sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264
     # via reuse
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index f874b2ed475..c2f5a87b123 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -40,9 +40,9 @@ WORKDIR /
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-22/wasi-sdk-22.0-linux.tar.gz | \
+RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-23/wasi-sdk-23.0-x86_64-linux.tar.gz | \
   tar -xz
-ENV WASI_SDK_PATH=/wasi-sdk-22.0
+ENV WASI_SDK_PATH=/wasi-sdk-23.0-x86_64-linux
 
 ENV RUST_CONFIGURE_ARGS \
   --musl-root-x86_64=/usr/local/x86_64-linux-musl \
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index a6e12c6ff95..638f14ad53f 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -326,6 +326,7 @@ auto:
       NO_DEBUG_ASSERTIONS: 1
       NO_OVERFLOW_CHECKS: 1
       DIST_REQUIRE_ALL_TOOLS: 1
+      CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-macos-m1
 
   # This target only needs to support 11.0 and up as nothing else supports the hardware
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 869f75e923d..c8201d9bcfd 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -19,7 +19,7 @@ if [ "$NO_CHANGE_USER" = "" ]; then
     # already be running with the right user.
     #
     # For NO_CHANGE_USER done in the small number of Dockerfiles affected.
-    echo -e '[safe]\n\tdirectory = *' > /home/user/gitconfig
+    echo -e '[safe]\n\tdirectory = *' > /home/user/.gitconfig
 
     exec su --preserve-environment -c "env PATH=$PATH \"$0\"" user
   fi
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index 4a1c0916253..c02c9aebe7e 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -38,33 +38,10 @@ they will both appear in documentation.
 Rustdoc does not have a magic way to compile documentation 'as-if' you'd run it once for each
 platform (such a magic wand has been called the ['holy grail of rustdoc'][#1998]). Instead,
 it sees *all* of your code at once, the same way the Rust compiler would if you passed it
-`--cfg doc`. However, Rustdoc has a trick up its sleeve to handle platform-specific code if it
-*does* receive it.
-
-To document your crate, Rustdoc only needs to know the public signature of your functions.
-In particular, it doesn't have to know how any of your functions are implemented, so it ignores
-all type errors and name resolution errors with function bodies. Note that this does *not*
-work for anything outside a function body: since Rustdoc documents your types, it has to
-know what those types are! For example, this code will work regardless of the platform:
-
-```rust,ignore (platform-specific,rustdoc-specific-behavior)
-pub fn f() {
-    use std::os::windows::ffi::OsStrExt;
-}
-```
-
-but this will not, because the unknown type is part of the function signature:
-
-```rust,ignore (platform-specific,rustdoc-specific-behavior)
-pub fn f() -> std::os::windows::ffi::EncodeWide<'static> {
-    unimplemented!()
-}
-```
-
-For a more realistic example of code this allows, see [the rustdoc test suite][realistic-async].
+`--cfg doc`. The main difference is that rustdoc doesn't run all the compiler passes, meaning
+that some invalid code won't emit an error.
 
 [#1998]: https://github.com/rust-lang/rust/issues/1998
-[realistic-async]: https://github.com/rust-lang/rust/blob/b146000e910ccd60bdcde89363cb6aa14ecc0d95/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
 
 ## Add aliases for an item in documentation search
 
diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml
index a045be956ac..56cb5cddeea 100644
--- a/src/etc/test-float-parse/Cargo.toml
+++ b/src/etc/test-float-parse/Cargo.toml
@@ -4,11 +4,12 @@ version = "0.1.0"
 edition = "2021"
 publish = false
 
-[workspace]
-resolver = "1"
-
 [dependencies]
-rand = "0.8"
+indicatif = { version = "0.17.8", default-features = false }
+num = "0.4.3"
+rand = "0.8.5"
+rand_chacha = "0.3"
+rayon = "1"
 
 [lib]
 name = "test_float_parse"
diff --git a/src/etc/test-float-parse/README.md b/src/etc/test-float-parse/README.md
new file mode 100644
index 00000000000..21b20d0a072
--- /dev/null
+++ b/src/etc/test-float-parse/README.md
@@ -0,0 +1,55 @@
+# Float Parsing Tests
+
+These are tests designed to test decimal to float conversions (`dec2flt`) used
+by the standard library.
+
+It consistes of a collection of test generators that each generate a set of
+patterns intended to test a specific property. In addition, there are exhaustive
+tests (for <= `f32`) and fuzzers (for anything that can't be run exhaustively).
+
+The generators work as follows:
+
+- Each generator is a struct that lives somewhere in the `gen` module. Usually
+  it is generic over a float type.
+- These generators must implement `Iterator`, which should return a context type
+  that can be used to construct a test string (but usually not the string
+  itself).
+- They must also implement the `Generator` trait, which provides a method to
+  write test context to a string as a test case, as well as some extra metadata.
+
+  The split between context generation and string construction is so that we can
+  reuse string allocations.
+- Each generator gets registered once for each float type. Each of these
+  generators then get their iterator called, and each test case checked against
+  the float type's parse implementation.
+
+Some generators produce decimal strings, others create bit patterns that need to
+be bitcasted to the float type, which then uses its `Display` implementation to
+write to a string. For these, float to decimal (`flt2dec`) conversions also get
+tested, if unintentionally.
+
+For each test case, the following is done:
+
+- The test string is parsed to the float type using the standard library's
+  implementation.
+- The test string is parsed separately to a `BigRational`, which acts as a
+  representation with infinite precision.
+- The rational value then gets checked that it is within the float's
+  representable values (absolute value greater than the smallest number to round
+  to zero, but less less than the first value to round to infinity). If these
+  limits are exceeded, check that the parsed float reflects that.
+- For real nonzero numbers, the parsed float is converted into a rational using
+  `significand * 2^exponent`. It is then checked against the actual rational
+  value, and verified to be within half a bit's precision of the parsed value.
+  Also it is checked that ties round to even.
+
+This is all highly parallelized with `rayon`; test generators can run in
+parallel, and their tests get chunked and run in parallel.
+
+There is a simple command line that allows filtering which tests are run,
+setting the number of iterations for fuzzing tests, limiting failures, setting
+timeouts, etc. See `main.rs` or run with `--help` for options.
+
+Note that when running via `./x`, only tests that take less than a few minutes
+are run by default. Navigate to the crate (or pass `-C` to Cargo) and run it
+directly to run all tests or pass specific arguments.
diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py
deleted file mode 100755
index cc5e31a051f..00000000000
--- a/src/etc/test-float-parse/runtests.py
+++ /dev/null
@@ -1,394 +0,0 @@
-#!/usr/bin/env python3
-
-"""
-Testing dec2flt
-===============
-These are *really* extensive tests. Expect them to run for hours. Due to the
-nature of the problem (the input is a string of arbitrary length), exhaustive
-testing is not really possible. Instead, there are exhaustive tests for some
-classes of inputs for which that is feasible and a bunch of deterministic and
-random non-exhaustive tests for covering everything else.
-
-The actual tests (generating decimal strings and feeding them to dec2flt) is
-performed by a set of stand-along rust programs. This script compiles, runs,
-and supervises them. The programs report the strings they generate and the
-floating point numbers they converted those strings to, and this script
-checks that the results are correct.
-
-You can run specific tests rather than all of them by giving their names
-(without .rs extension) as command line parameters.
-
-Verification
-------------
-The tricky part is not generating those inputs but verifying the outputs.
-Comparing with the result of Python's float() does not cut it because
-(and this is apparently undocumented) although Python includes a version of
-Martin Gay's code including the decimal-to-float part, it doesn't actually use
-it for float() (only for round()) instead relying on the system scanf() which
-is not necessarily completely accurate.
-
-Instead, we take the input and compute the true value with bignum arithmetic
-(as a fraction, using the ``fractions`` module).
-
-Given an input string and the corresponding float computed via Rust, simply
-decode the float into f * 2^k (for integers f, k) and the ULP.
-We can now easily compute the error and check if it is within 0.5 ULP as it
-should be. Zero and infinites are handled similarly:
-
-- If the approximation is 0.0, the exact value should be *less or equal*
-  half the smallest denormal float: the smallest denormal floating point
-  number has an odd mantissa (00...001) and thus half of that is rounded
-  to 00...00, i.e., zero.
-- If the approximation is Inf, the exact value should be *greater or equal*
-  to the largest finite float + 0.5 ULP: the largest finite float has an odd
-  mantissa (11...11), so that plus half an ULP is rounded up to the nearest
-  even number, which overflows.
-
-Implementation details
-----------------------
-This directory contains a set of single-file Rust programs that perform
-tests with a particular class of inputs. Each is compiled and run without
-parameters, outputs (f64, f32, decimal) pairs to verify externally, and
-in any case either exits gracefully or with a panic.
-
-If a test binary writes *anything at all* to stderr or exits with an
-exit code that's not 0, the test fails.
-The output on stdout is treated as (f64, f32, decimal) record, encoded thusly:
-
-- First, the bits of the f64 encoded as an ASCII hex string.
-- Second, the bits of the f32 encoded as an ASCII hex string.
-- Then the corresponding string input, in ASCII
-- The record is terminated with a newline.
-
-Incomplete records are an error. Not-a-Number bit patterns are invalid too.
-
-The tests run serially but the validation for a single test is parallelized
-with ``multiprocessing``. Each test is launched as a subprocess.
-One thread supervises it: Accepts and enqueues records to validate, observe
-stderr, and waits for the process to exit. A set of worker processes perform
-the validation work for the outputs enqueued there. Another thread listens
-for progress updates from the workers.
-
-Known issues
-------------
-Some errors (e.g., NaN outputs) aren't handled very gracefully.
-Also, if there is an exception or the process is interrupted (at least on
-Windows) the worker processes are leaked and stick around forever.
-They're only a few megabytes each, but still, this script should not be run
-if you aren't prepared to manually kill a lot of orphaned processes.
-"""
-from __future__ import print_function
-import sys
-import os.path
-import time
-import struct
-from fractions import Fraction
-from collections import namedtuple
-from subprocess import Popen, check_call, PIPE
-from glob import glob
-import multiprocessing
-import threading
-import ctypes
-import binascii
-
-try:  # Python 3
-    import queue as Queue
-except ImportError:  # Python 2
-    import Queue
-
-NUM_WORKERS = 2
-UPDATE_EVERY_N = 50000
-INF = namedtuple('INF', '')()
-NEG_INF = namedtuple('NEG_INF', '')()
-ZERO = namedtuple('ZERO', '')()
-MAILBOX = None  # The queue for reporting errors to the main process.
-STDOUT_LOCK = threading.Lock()
-test_name = None
-child_processes = []
-exit_status = 0
-
-def msg(*args):
-    with STDOUT_LOCK:
-        print("[" + test_name + "]", *args)
-        sys.stdout.flush()
-
-
-def write_errors():
-    global exit_status
-    f = open("errors.txt", 'w')
-    have_seen_error = False
-    while True:
-        args = MAILBOX.get()
-        if args is None:
-            f.close()
-            break
-        print(*args, file=f)
-        f.flush()
-        if not have_seen_error:
-            have_seen_error = True
-            msg("Something is broken:", *args)
-            msg("Future errors will be logged to errors.txt")
-            exit_status = 101
-
-
-def cargo():
-    print("compiling tests")
-    sys.stdout.flush()
-    check_call(['cargo', 'build', '--release'])
-
-
-def run(test):
-    global test_name
-    test_name = test
-
-    t0 = time.perf_counter()
-    msg("setting up supervisor")
-    command = ['cargo', 'run', '--bin', test, '--release']
-    proc = Popen(command, bufsize=1<<20 , stdin=PIPE, stdout=PIPE, stderr=PIPE)
-    done = multiprocessing.Value(ctypes.c_bool)
-    queue = multiprocessing.Queue(maxsize=5)#(maxsize=1024)
-    workers = []
-    for n in range(NUM_WORKERS):
-        worker = multiprocessing.Process(name='Worker-' + str(n + 1),
-                                         target=init_worker,
-                                         args=[test, MAILBOX, queue, done])
-        workers.append(worker)
-        child_processes.append(worker)
-    for worker in workers:
-        worker.start()
-    msg("running test")
-    interact(proc, queue)
-    with done.get_lock():
-        done.value = True
-    for worker in workers:
-        worker.join()
-    msg("python is done")
-    assert queue.empty(), "did not validate everything"
-    dt = time.perf_counter() - t0
-    msg("took", round(dt, 3), "seconds")
-
-
-def interact(proc, queue):
-    n = 0
-    while proc.poll() is None:
-        line = proc.stdout.readline()
-        if not line:
-            continue
-        assert line.endswith(b'\n'), "incomplete line: " + repr(line)
-        queue.put(line)
-        n += 1
-        if n % UPDATE_EVERY_N == 0:
-            msg("got", str(n // 1000) + "k", "records")
-    msg("rust is done. exit code:", proc.returncode)
-    rest, stderr = proc.communicate()
-    if stderr:
-        msg("rust stderr output:", stderr)
-    for line in rest.split(b'\n'):
-        if not line:
-            continue
-        queue.put(line)
-
-
-def main():
-    global MAILBOX
-    files = glob('src/bin/*.rs')
-    basenames = [os.path.basename(i) for i in files]
-    all_tests = [os.path.splitext(f)[0] for f in basenames if not f.startswith('_')]
-    args = sys.argv[1:]
-    if args:
-        tests = [test for test in all_tests if test in args]
-    else:
-        tests = all_tests
-    if not tests:
-        print("Error: No tests to run")
-        sys.exit(1)
-    # Compile first for quicker feedback
-    cargo()
-    # Set up mailbox once for all tests
-    MAILBOX = multiprocessing.Queue()
-    mailman = threading.Thread(target=write_errors)
-    mailman.daemon = True
-    mailman.start()
-    for test in tests:
-        run(test)
-    MAILBOX.put(None)
-    mailman.join()
-
-
-# ---- Worker thread code ----
-
-
-POW2 = { e: Fraction(2) ** e for e in range(-1100, 1100) }
-HALF_ULP = { e: (Fraction(2) ** e)/2 for e in range(-1100, 1100) }
-DONE_FLAG = None
-
-
-def send_error_to_supervisor(*args):
-    MAILBOX.put(args)
-
-
-def init_worker(test, mailbox, queue, done):
-    global test_name, MAILBOX, DONE_FLAG
-    test_name = test
-    MAILBOX = mailbox
-    DONE_FLAG = done
-    do_work(queue)
-
-
-def is_done():
-    with DONE_FLAG.get_lock():
-        return DONE_FLAG.value
-
-
-def do_work(queue):
-    while True:
-        try:
-            line = queue.get(timeout=0.01)
-        except Queue.Empty:
-            if queue.empty() and is_done():
-                return
-            else:
-                continue
-        bin64, bin32, text = line.rstrip().split()
-        validate(bin64, bin32, text.decode('utf-8'))
-
-
-def decode_binary64(x):
-    """
-    Turn a IEEE 754 binary64 into (mantissa, exponent), except 0.0 and
-    infinity (positive and negative), which return ZERO, INF, and NEG_INF
-    respectively.
-    """
-    x = binascii.unhexlify(x)
-    assert len(x) == 8, repr(x)
-    [bits] = struct.unpack(b'>Q', x)
-    if bits == 0:
-        return ZERO
-    exponent = (bits >> 52) & 0x7FF
-    negative = bits >> 63
-    low_bits = bits & 0xFFFFFFFFFFFFF
-    if exponent == 0:
-        mantissa = low_bits
-        exponent += 1
-        if mantissa == 0:
-            return ZERO
-    elif exponent == 0x7FF:
-        assert low_bits == 0, "NaN"
-        if negative:
-            return NEG_INF
-        else:
-            return INF
-    else:
-        mantissa = low_bits | (1 << 52)
-    exponent -= 1023 + 52
-    if negative:
-        mantissa = -mantissa
-    return (mantissa, exponent)
-
-
-def decode_binary32(x):
-    """
-    Turn a IEEE 754 binary32 into (mantissa, exponent), except 0.0 and
-    infinity (positive and negative), which return ZERO, INF, and NEG_INF
-    respectively.
-    """
-    x = binascii.unhexlify(x)
-    assert len(x) == 4, repr(x)
-    [bits] = struct.unpack(b'>I', x)
-    if bits == 0:
-        return ZERO
-    exponent = (bits >> 23) & 0xFF
-    negative = bits >> 31
-    low_bits = bits & 0x7FFFFF
-    if exponent == 0:
-        mantissa = low_bits
-        exponent += 1
-        if mantissa == 0:
-            return ZERO
-    elif exponent == 0xFF:
-        if negative:
-            return NEG_INF
-        else:
-            return INF
-    else:
-        mantissa = low_bits | (1 << 23)
-    exponent -= 127 + 23
-    if negative:
-        mantissa = -mantissa
-    return (mantissa, exponent)
-
-
-MIN_SUBNORMAL_DOUBLE = Fraction(2) ** -1074
-MIN_SUBNORMAL_SINGLE = Fraction(2) ** -149  # XXX unsure
-MAX_DOUBLE = (2 - Fraction(2) ** -52) * (2 ** 1023)
-MAX_SINGLE = (2 - Fraction(2) ** -23) * (2 ** 127)
-MAX_ULP_DOUBLE = 1023 - 52
-MAX_ULP_SINGLE = 127 - 23
-DOUBLE_ZERO_CUTOFF = MIN_SUBNORMAL_DOUBLE / 2
-DOUBLE_INF_CUTOFF = MAX_DOUBLE + 2 ** (MAX_ULP_DOUBLE - 1)
-SINGLE_ZERO_CUTOFF = MIN_SUBNORMAL_SINGLE / 2
-SINGLE_INF_CUTOFF = MAX_SINGLE + 2 ** (MAX_ULP_SINGLE - 1)
-
-def validate(bin64, bin32, text):
-    try:
-        double = decode_binary64(bin64)
-    except AssertionError:
-        print(bin64, bin32, text)
-        raise
-    single = decode_binary32(bin32)
-    real = Fraction(text)
-
-    if double is ZERO:
-        if real > DOUBLE_ZERO_CUTOFF:
-            record_special_error(text, "f64 zero")
-    elif double is INF:
-        if real < DOUBLE_INF_CUTOFF:
-            record_special_error(text, "f64 inf")
-    elif double is NEG_INF:
-        if -real < DOUBLE_INF_CUTOFF:
-            record_special_error(text, "f64 -inf")
-    elif len(double) == 2:
-        sig, k = double
-        validate_normal(text, real, sig, k, "f64")
-    else:
-        assert 0, "didn't handle binary64"
-    if single is ZERO:
-        if real > SINGLE_ZERO_CUTOFF:
-            record_special_error(text, "f32 zero")
-    elif single is INF:
-        if real < SINGLE_INF_CUTOFF:
-            record_special_error(text, "f32 inf")
-    elif single is NEG_INF:
-        if -real < SINGLE_INF_CUTOFF:
-            record_special_error(text, "f32 -inf")
-    elif len(single) == 2:
-        sig, k = single
-        validate_normal(text, real, sig, k, "f32")
-    else:
-        assert 0, "didn't handle binary32"
-
-def record_special_error(text, descr):
-    send_error_to_supervisor(text.strip(), "wrongly rounded to", descr)
-
-
-def validate_normal(text, real, sig, k, kind):
-    approx = sig * POW2[k]
-    error = abs(approx - real)
-    if error > HALF_ULP[k]:
-        record_normal_error(text, error, k, kind)
-
-
-def record_normal_error(text, error, k, kind):
-    one_ulp = HALF_ULP[k + 1]
-    assert one_ulp == 2 * HALF_ULP[k]
-    relative_error = error / one_ulp
-    text = text.strip()
-    try:
-        err_repr = float(relative_error)
-    except ValueError:
-        err_repr = str(err_repr).replace('/', ' / ')
-    send_error_to_supervisor(err_repr, "ULP error on", text, "(" + kind + ")")
-
-
-if __name__ == '__main__':
-    main()
diff --git a/src/etc/test-float-parse/src/bin/few-ones.rs b/src/etc/test-float-parse/src/bin/few-ones.rs
deleted file mode 100644
index 6bb406a5947..00000000000
--- a/src/etc/test-float-parse/src/bin/few-ones.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use test_float_parse::validate;
-
-fn main() {
-    let mut pow = vec![];
-    for i in 0..63 {
-        pow.push(1u64 << i);
-    }
-    for a in &pow {
-        for b in &pow {
-            for c in &pow {
-                validate(&(a | b | c).to_string());
-            }
-        }
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/huge-pow10.rs b/src/etc/test-float-parse/src/bin/huge-pow10.rs
deleted file mode 100644
index 722a24ffcd8..00000000000
--- a/src/etc/test-float-parse/src/bin/huge-pow10.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use test_float_parse::validate;
-
-fn main() {
-    for e in 300..310 {
-        for i in 0..100000 {
-            validate(&format!("{}e{}", i, e));
-        }
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/long-fractions.rs b/src/etc/test-float-parse/src/bin/long-fractions.rs
deleted file mode 100644
index c715bc1ac2b..00000000000
--- a/src/etc/test-float-parse/src/bin/long-fractions.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use std::char;
-use test_float_parse::validate;
-
-fn main() {
-    for n in 0..10 {
-        let digit = char::from_digit(n, 10).unwrap();
-        let mut s = "0.".to_string();
-        for _ in 0..400 {
-            s.push(digit);
-            if s.parse::<f64>().is_ok() {
-                validate(&s);
-            }
-        }
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/many-digits.rs b/src/etc/test-float-parse/src/bin/many-digits.rs
deleted file mode 100644
index ba166fd5607..00000000000
--- a/src/etc/test-float-parse/src/bin/many-digits.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-extern crate rand;
-
-use rand::distributions::{Range, Sample};
-use rand::{IsaacRng, Rng, SeedableRng};
-use std::char;
-use test_float_parse::{validate, SEED};
-
-fn main() {
-    let mut rnd = IsaacRng::from_seed(&SEED);
-    let mut range = Range::new(0, 10);
-    for _ in 0..5_000_000u64 {
-        let num_digits = rnd.gen_range(100, 400);
-        let digits = gen_digits(num_digits, &mut range, &mut rnd);
-        validate(&digits);
-    }
-}
-
-fn gen_digits<R: Rng>(n: u32, range: &mut Range<u32>, rnd: &mut R) -> String {
-    let mut s = String::new();
-    for _ in 0..n {
-        let digit = char::from_digit(range.sample(rnd), 10).unwrap();
-        s.push(digit);
-    }
-    s
-}
diff --git a/src/etc/test-float-parse/src/bin/rand-f64.rs b/src/etc/test-float-parse/src/bin/rand-f64.rs
deleted file mode 100644
index 6991e8be15e..00000000000
--- a/src/etc/test-float-parse/src/bin/rand-f64.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-extern crate rand;
-
-use rand::{IsaacRng, Rng, SeedableRng};
-use std::mem::transmute;
-use test_float_parse::{validate, SEED};
-
-fn main() {
-    let mut rnd = IsaacRng::from_seed(&SEED);
-    let mut i = 0;
-    while i < 10_000_000 {
-        let bits = rnd.next_u64();
-        let x: f64 = unsafe { transmute(bits) };
-        if x.is_finite() {
-            validate(&format!("{:e}", x));
-            i += 1;
-        }
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/short-decimals.rs b/src/etc/test-float-parse/src/bin/short-decimals.rs
deleted file mode 100644
index 49084eb35e8..00000000000
--- a/src/etc/test-float-parse/src/bin/short-decimals.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use test_float_parse::validate;
-
-fn main() {
-    // Skip e = 0 because small-u32 already does those.
-    for e in 1..301 {
-        for i in 0..10000 {
-            // If it ends in zeros, the parser will strip those (and adjust the exponent),
-            // which almost always (except for exponents near +/- 300) result in an input
-            // equivalent to something we already generate in a different way.
-            if i % 10 == 0 {
-                continue;
-            }
-            validate(&format!("{}e{}", i, e));
-            validate(&format!("{}e-{}", i, e));
-        }
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/subnorm.rs b/src/etc/test-float-parse/src/bin/subnorm.rs
deleted file mode 100644
index ac88747eacd..00000000000
--- a/src/etc/test-float-parse/src/bin/subnorm.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use std::mem::transmute;
-use test_float_parse::validate;
-
-fn main() {
-    for bits in 0u32..(1 << 21) {
-        let single: f32 = unsafe { transmute(bits) };
-        validate(&format!("{:e}", single));
-        let double: f64 = unsafe { transmute(bits as u64) };
-        validate(&format!("{:e}", double));
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/tiny-pow10.rs b/src/etc/test-float-parse/src/bin/tiny-pow10.rs
deleted file mode 100644
index fb6ba166380..00000000000
--- a/src/etc/test-float-parse/src/bin/tiny-pow10.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use test_float_parse::validate;
-
-fn main() {
-    for e in 301..327 {
-        for i in 0..100000 {
-            validate(&format!("{}e-{}", i, e));
-        }
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/u32-small.rs b/src/etc/test-float-parse/src/bin/u32-small.rs
deleted file mode 100644
index 5ec9d1eea5f..00000000000
--- a/src/etc/test-float-parse/src/bin/u32-small.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-use test_float_parse::validate;
-
-fn main() {
-    for i in 0..(1 << 19) {
-        validate(&i.to_string());
-    }
-}
diff --git a/src/etc/test-float-parse/src/bin/u64-pow2.rs b/src/etc/test-float-parse/src/bin/u64-pow2.rs
deleted file mode 100644
index 984e49200cd..00000000000
--- a/src/etc/test-float-parse/src/bin/u64-pow2.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use test_float_parse::validate;
-
-fn main() {
-    for exp in 19..64 {
-        let power: u64 = 1 << exp;
-        validate(&power.to_string());
-        for offset in 1..123 {
-            validate(&(power + offset).to_string());
-            validate(&(power - offset).to_string());
-        }
-    }
-    for offset in 0..123 {
-        validate(&(u64::MAX - offset).to_string());
-    }
-}
diff --git a/src/etc/test-float-parse/src/gen/exhaustive.rs b/src/etc/test-float-parse/src/gen/exhaustive.rs
new file mode 100644
index 00000000000..5d4b6df8e59
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/exhaustive.rs
@@ -0,0 +1,43 @@
+use std::fmt::Write;
+use std::ops::RangeInclusive;
+
+use crate::{Float, Generator, Int};
+
+/// Test every possible bit pattern. This is infeasible to run on any float types larger than
+/// `f32` (which takes about an hour).
+pub struct Exhaustive<F: Float> {
+    iter: RangeInclusive<F::Int>,
+}
+
+impl<F: Float> Generator<F> for Exhaustive<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    const NAME: &'static str = "exhaustive";
+    const SHORT_NAME: &'static str = "exhaustive";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        F::Int::MAX.try_into().unwrap_or(u64::MAX)
+    }
+
+    fn new() -> Self {
+        Self { iter: F::Int::ZERO..=F::Int::MAX }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for Exhaustive<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(F::from_bits(self.iter.next()?))
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/exponents.rs b/src/etc/test-float-parse/src/gen/exponents.rs
new file mode 100644
index 00000000000..3748e9d380c
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/exponents.rs
@@ -0,0 +1,95 @@
+use std::fmt::Write;
+use std::ops::RangeInclusive;
+
+use crate::traits::BoxGenIter;
+use crate::{Float, Generator};
+
+const SMALL_COEFF_MAX: i32 = 10_000;
+const SMALL_EXP_MAX: i32 = 300;
+
+const SMALL_COEFF_RANGE: RangeInclusive<i32> = (-SMALL_COEFF_MAX)..=SMALL_COEFF_MAX;
+const SMALL_EXP_RANGE: RangeInclusive<i32> = (-SMALL_EXP_MAX)..=SMALL_EXP_MAX;
+
+const LARGE_COEFF_RANGE: RangeInclusive<u32> = 0..=100_000;
+const LARGE_EXP_RANGE: RangeInclusive<u32> = 300..=350;
+
+/// Check exponential values around zero.
+pub struct SmallExponents<F: Float> {
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> Generator<F> for SmallExponents<F> {
+    const NAME: &'static str = "small exponents";
+    const SHORT_NAME: &'static str = "small exp";
+
+    /// `(coefficient, exponent)`
+    type WriteCtx = (i32, i32);
+
+    fn total_tests() -> u64 {
+        ((1 + SMALL_COEFF_RANGE.end() - SMALL_COEFF_RANGE.start())
+            * (1 + SMALL_EXP_RANGE.end() - SMALL_EXP_RANGE.start()))
+        .try_into()
+        .unwrap()
+    }
+
+    fn new() -> Self {
+        let iter = SMALL_EXP_RANGE.flat_map(|exp| SMALL_COEFF_RANGE.map(move |coeff| (coeff, exp)));
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        let (coeff, exp) = ctx;
+        write!(s, "{coeff}e{exp}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for SmallExponents<F> {
+    type Item = (i32, i32);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+/// Check exponential values further from zero.
+pub struct LargeExponents<F: Float> {
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> Generator<F> for LargeExponents<F> {
+    const NAME: &'static str = "large positive exponents";
+    const SHORT_NAME: &'static str = "large exp";
+
+    /// `(coefficient, exponent, is_positive)`
+    type WriteCtx = (u32, u32, bool);
+
+    fn total_tests() -> u64 {
+        ((1 + LARGE_EXP_RANGE.end() - LARGE_EXP_RANGE.start())
+            * (1 + LARGE_COEFF_RANGE.end() - LARGE_COEFF_RANGE.start())
+            * 2)
+        .into()
+    }
+
+    fn new() -> Self {
+        let iter = LARGE_EXP_RANGE
+            .flat_map(|exp| LARGE_COEFF_RANGE.map(move |coeff| (coeff, exp)))
+            .flat_map(|(coeff, exp)| [(coeff, exp, false), (coeff, exp, true)]);
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        let (coeff, exp, is_positive) = ctx;
+        let sign = if is_positive { "" } else { "-" };
+        write!(s, "{sign}{coeff}e{exp}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for LargeExponents<F> {
+    type Item = (u32, u32, bool);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/fuzz.rs b/src/etc/test-float-parse/src/gen/fuzz.rs
new file mode 100644
index 00000000000..213bcfc64af
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/fuzz.rs
@@ -0,0 +1,88 @@
+use std::any::{type_name, TypeId};
+use std::collections::BTreeMap;
+use std::fmt::Write;
+use std::marker::PhantomData;
+use std::ops::Range;
+use std::sync::Mutex;
+
+use rand::distributions::{Distribution, Standard};
+use rand::Rng;
+use rand_chacha::rand_core::SeedableRng;
+use rand_chacha::ChaCha8Rng;
+
+use crate::{Float, Generator, Int, SEED};
+
+/// Mapping of float types to the number of iterations that should be run.
+///
+/// We could probably make `Generator::new` take an argument instead of the global state,
+/// but we only load this once so it works.
+static FUZZ_COUNTS: Mutex<BTreeMap<TypeId, u64>> = Mutex::new(BTreeMap::new());
+
+/// Generic fuzzer; just tests deterministic random bit patterns N times.
+pub struct Fuzz<F> {
+    iter: Range<u64>,
+    rng: ChaCha8Rng,
+    /// Allow us to use generics in `Iterator`.
+    marker: PhantomData<F>,
+}
+
+impl<F: Float> Fuzz<F> {
+    /// Register how many iterations the fuzzer should run for a type. Uses some logic by
+    /// default, but if `from_cfg` is `Some`, that will be used instead.
+    pub fn set_iterations(from_cfg: Option<u64>) {
+        let count = if let Some(cfg_count) = from_cfg {
+            cfg_count
+        } else if F::BITS <= crate::MAX_BITS_FOR_EXHAUUSTIVE {
+            // If we run exhaustively, still fuzz but only do half as many bits. The only goal here is
+            // to catch failures from e.g. high bit patterns before exhaustive tests would get to them.
+            (F::Int::MAX >> (F::BITS / 2)).try_into().unwrap()
+        } else {
+            // Eveything bigger gets a fuzz test with as many iterations as `f32` exhaustive.
+            u32::MAX.into()
+        };
+
+        let _ = FUZZ_COUNTS.lock().unwrap().insert(TypeId::of::<F>(), count);
+    }
+}
+
+impl<F: Float> Generator<F> for Fuzz<F>
+where
+    Standard: Distribution<<F as Float>::Int>,
+{
+    const NAME: &'static str = "fuzz";
+    const SHORT_NAME: &'static str = "fuzz";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        *FUZZ_COUNTS
+            .lock()
+            .unwrap()
+            .get(&TypeId::of::<F>())
+            .unwrap_or_else(|| panic!("missing fuzz count for {}", type_name::<F>()))
+    }
+
+    fn new() -> Self {
+        let rng = ChaCha8Rng::from_seed(SEED);
+
+        Self { iter: 0..Self::total_tests(), rng, marker: PhantomData }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for Fuzz<F>
+where
+    Standard: Distribution<<F as Float>::Int>,
+{
+    type Item = <Self as Generator<F>>::WriteCtx;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let _ = self.iter.next()?;
+        let i: F::Int = self.rng.gen();
+
+        Some(F::from_bits(i))
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/integers.rs b/src/etc/test-float-parse/src/gen/integers.rs
new file mode 100644
index 00000000000..070d188e88c
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/integers.rs
@@ -0,0 +1,104 @@
+use std::fmt::Write;
+use std::ops::{Range, RangeInclusive};
+
+use crate::traits::BoxGenIter;
+use crate::{Float, Generator};
+
+const SMALL_MAX_POW2: u32 = 19;
+
+/// All values up to the max power of two
+const SMALL_VALUES: RangeInclusive<i32> = {
+    let max = 1i32 << SMALL_MAX_POW2;
+    (-max)..=max
+};
+
+/// Large values only get tested around powers of two
+const LARGE_POWERS: Range<u32> = SMALL_MAX_POW2..128;
+
+/// We perturbe each large value around these ranges
+const LARGE_PERTURBATIONS: RangeInclusive<i128> = -256..=256;
+
+/// Test all integers up to `2 ^ MAX_POW2`
+pub struct SmallInt {
+    iter: RangeInclusive<i32>,
+}
+
+impl<F: Float> Generator<F> for SmallInt {
+    const NAME: &'static str = "small integer values";
+    const SHORT_NAME: &'static str = "int small";
+
+    type WriteCtx = i32;
+
+    fn total_tests() -> u64 {
+        (SMALL_VALUES.end() + 1 - SMALL_VALUES.start()).try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        Self { iter: SMALL_VALUES }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx}").unwrap();
+    }
+}
+
+impl Iterator for SmallInt {
+    type Item = i32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+/// Test much bigger integers than [`SmallInt`].
+pub struct LargeInt<F: Float> {
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> LargeInt<F> {
+    const EDGE_CASES: [i128; 7] = [
+        i32::MIN as i128,
+        i32::MAX as i128,
+        i64::MIN as i128,
+        i64::MAX as i128,
+        u64::MAX as i128,
+        i128::MIN,
+        i128::MAX,
+    ];
+}
+
+impl<F: Float> Generator<F> for LargeInt<F> {
+    const NAME: &'static str = "large integer values";
+    const SHORT_NAME: &'static str = "int large";
+
+    type WriteCtx = i128;
+
+    fn total_tests() -> u64 {
+        u64::try_from(
+            (i128::from(LARGE_POWERS.end - LARGE_POWERS.start)
+                + i128::try_from(Self::EDGE_CASES.len()).unwrap())
+                * (LARGE_PERTURBATIONS.end() + 1 - LARGE_PERTURBATIONS.start()),
+        )
+        .unwrap()
+    }
+
+    fn new() -> Self {
+        let iter = LARGE_POWERS
+            .map(|pow| 1i128 << pow)
+            .chain(Self::EDGE_CASES)
+            .flat_map(|base| LARGE_PERTURBATIONS.map(move |perturb| base.saturating_add(perturb)));
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx}").unwrap();
+    }
+}
+impl<F: Float> Iterator for LargeInt<F> {
+    type Item = i128;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/long_fractions.rs b/src/etc/test-float-parse/src/gen/long_fractions.rs
new file mode 100644
index 00000000000..b75148b779c
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/long_fractions.rs
@@ -0,0 +1,58 @@
+use std::char;
+use std::fmt::Write;
+
+use crate::{Float, Generator};
+
+/// Number of decimal digits to check (all of them).
+const MAX_DIGIT: u32 = 9;
+/// Test with this many decimals in the string.
+const MAX_DECIMALS: usize = 410;
+const PREFIX: &str = "0.";
+
+/// Test e.g. `0.1`, `0.11`, `0.111`, `0.1111`, ..., `0.2`, `0.22`, ...
+pub struct RepeatingDecimal {
+    digit: u32,
+    buf: String,
+}
+
+impl<F: Float> Generator<F> for RepeatingDecimal {
+    const NAME: &'static str = "repeating decimal";
+    const SHORT_NAME: &'static str = "dec rep";
+
+    type WriteCtx = String;
+
+    fn total_tests() -> u64 {
+        u64::from(MAX_DIGIT + 1) * u64::try_from(MAX_DECIMALS + 1).unwrap() + 1
+    }
+
+    fn new() -> Self {
+        Self { digit: 0, buf: PREFIX.to_owned() }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        *s = ctx;
+    }
+}
+
+impl Iterator for RepeatingDecimal {
+    type Item = String;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.digit > MAX_DIGIT {
+            return None;
+        }
+
+        let digit = self.digit;
+        let inc_digit = self.buf.len() - PREFIX.len() > MAX_DECIMALS;
+
+        if inc_digit {
+            // Reset the string
+            self.buf.clear();
+            self.digit += 1;
+            self.buf.write_str(PREFIX).unwrap();
+        }
+
+        self.buf.push(char::from_digit(digit, 10).unwrap());
+        Some(self.buf.clone())
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/many_digits.rs b/src/etc/test-float-parse/src/gen/many_digits.rs
new file mode 100644
index 00000000000..aab8d5d704b
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/many_digits.rs
@@ -0,0 +1,84 @@
+use std::char;
+use std::fmt::Write;
+use std::marker::PhantomData;
+use std::ops::{Range, RangeInclusive};
+
+use rand::distributions::{Distribution, Uniform};
+use rand::{Rng, SeedableRng};
+use rand_chacha::ChaCha8Rng;
+
+use crate::{Float, Generator, SEED};
+
+/// Total iterations
+const ITERATIONS: u64 = 5_000_000;
+
+/// Possible lengths of the string, excluding decimals and exponents
+const POSSIBLE_NUM_DIGITS: RangeInclusive<usize> = 100..=400;
+
+/// Range of possible exponents
+const EXP_RANGE: Range<i32> = -4500..4500;
+
+/// Try strings of random digits.
+pub struct RandDigits<F> {
+    rng: ChaCha8Rng,
+    iter: Range<u64>,
+    uniform: Uniform<u32>,
+    /// Allow us to use generics in `Iterator`.
+    marker: PhantomData<F>,
+}
+
+impl<F: Float> Generator<F> for RandDigits<F> {
+    const NAME: &'static str = "random digits";
+
+    const SHORT_NAME: &'static str = "rand digits";
+
+    type WriteCtx = String;
+
+    fn total_tests() -> u64 {
+        ITERATIONS
+    }
+
+    fn new() -> Self {
+        let rng = ChaCha8Rng::from_seed(SEED);
+        let range = Uniform::from(0..10);
+
+        Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        *s = ctx;
+    }
+}
+
+impl<F: Float> Iterator for RandDigits<F> {
+    type Item = String;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let _ = self.iter.next()?;
+        let num_digits = self.rng.gen_range(POSSIBLE_NUM_DIGITS);
+        let has_decimal = self.rng.gen_bool(0.2);
+        let has_exp = self.rng.gen_bool(0.2);
+
+        let dec_pos = if has_decimal { Some(self.rng.gen_range(0..num_digits)) } else { None };
+
+        let mut s = String::with_capacity(num_digits);
+
+        for pos in 0..num_digits {
+            let digit = char::from_digit(self.uniform.sample(&mut self.rng), 10).unwrap();
+            s.push(digit);
+
+            if let Some(dec_pos) = dec_pos {
+                if pos == dec_pos {
+                    s.push('.');
+                }
+            }
+        }
+
+        if has_exp {
+            let exp = self.rng.gen_range(EXP_RANGE);
+            write!(s, "e{exp}").unwrap();
+        }
+
+        Some(s)
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/sparse.rs b/src/etc/test-float-parse/src/gen/sparse.rs
new file mode 100644
index 00000000000..389b71056a3
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/sparse.rs
@@ -0,0 +1,100 @@
+use std::fmt::Write;
+
+use crate::traits::BoxGenIter;
+use crate::{Float, Generator};
+
+const POWERS_OF_TWO: [u128; 128] = make_powers_of_two();
+
+const fn make_powers_of_two() -> [u128; 128] {
+    let mut ret = [0; 128];
+    let mut i = 0;
+    while i < 128 {
+        ret[i] = 1 << i;
+        i += 1;
+    }
+
+    ret
+}
+
+/// Can't clone this result because of lifetime errors, just use a macro.
+macro_rules! pow_iter {
+    () => {
+        (0..F::BITS).map(|i| F::Int::try_from(POWERS_OF_TWO[i as usize]).unwrap())
+    };
+}
+
+/// Test all numbers that include three 1s in the binary representation as integers.
+pub struct FewOnesInt<F: Float>
+where
+    FewOnesInt<F>: Generator<F>,
+{
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> Generator<F> for FewOnesInt<F>
+where
+    <F::Int as TryFrom<u128>>::Error: std::fmt::Debug,
+{
+    const NAME: &'static str = "few ones int";
+    const SHORT_NAME: &'static str = "few ones int";
+
+    type WriteCtx = F::Int;
+
+    fn total_tests() -> u64 {
+        u64::from(F::BITS).pow(3)
+    }
+
+    fn new() -> Self {
+        let iter = pow_iter!()
+            .flat_map(move |a| pow_iter!().map(move |b| (a, b)))
+            .flat_map(move |(a, b)| pow_iter!().map(move |c| (a, b, c)))
+            .map(|(a, b, c)| a | b | c);
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for FewOnesInt<F> {
+    type Item = F::Int;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+/// Similar to `FewOnesInt` except test those bit patterns as a float.
+pub struct FewOnesFloat<F: Float>(FewOnesInt<F>);
+
+impl<F: Float> Generator<F> for FewOnesFloat<F>
+where
+    <F::Int as TryFrom<u128>>::Error: std::fmt::Debug,
+{
+    const NAME: &'static str = "few ones float";
+    const SHORT_NAME: &'static str = "few ones float";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        FewOnesInt::<F>::total_tests()
+    }
+
+    fn new() -> Self {
+        Self(FewOnesInt::new())
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for FewOnesFloat<F> {
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next().map(|i| F::from_bits(i))
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/spot_checks.rs b/src/etc/test-float-parse/src/gen/spot_checks.rs
new file mode 100644
index 00000000000..18691f9d6cf
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/spot_checks.rs
@@ -0,0 +1,101 @@
+use std::fmt::Write;
+
+use crate::traits::{Float, Generator};
+
+const SPECIAL: &[&str] = &[
+    "inf", "Inf", "iNf", "INF", "-inf", "-Inf", "-iNf", "-INF", "+inf", "+Inf", "+iNf", "+INF",
+    "nan", "NaN", "NAN", "nAn", "-nan", "-NaN", "-NAN", "-nAn", "+nan", "+NaN", "+NAN", "+nAn",
+    "1", "-1", "+1", "1e1", "-1e1", "+1e1", "1e-1", "-1e-1", "+1e-1", "1e+1", "-1e+1", "+1e+1",
+    "1E1", "-1E1", "+1E1", "1E-1", "-1E-1", "+1E-1", "1E+1", "-1E+1", "+1E+1", "0", "-0", "+0",
+];
+
+/// Check various non-numeric special strings.
+pub struct Special {
+    iter: std::slice::Iter<'static, &'static str>,
+}
+
+impl<F: Float> Generator<F> for Special {
+    const NAME: &'static str = "special values";
+
+    const SHORT_NAME: &'static str = "special";
+
+    type WriteCtx = &'static str;
+
+    fn total_tests() -> u64 {
+        SPECIAL.len().try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        Self { iter: SPECIAL.iter() }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        s.write_str(ctx).unwrap();
+    }
+}
+
+impl Iterator for Special {
+    type Item = &'static str;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next().copied()
+    }
+}
+
+/// Strings that we know have failed in the past
+const REGRESSIONS: &[&str] = &[
+    // From <https://github.com/rust-lang/rust/issues/31407>
+    "1234567890123456789012345678901234567890e-340",
+    "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308",
+    "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308",
+    "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001",
+    "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999",
+    "2.47032822920623272e-324",
+    "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316",
+    "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319",
+    "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310",
+    "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319",
+    "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324",
+    "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324",
+    "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324",
+    "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324",
+    "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324",
+    "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324",
+    "94393431193180696942841837085033647913224148539854e-358",
+    "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075",
+    "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281249",
+    "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251",
+];
+
+/// Check items that failed in the past.
+pub struct RegressionCheck {
+    iter: std::slice::Iter<'static, &'static str>,
+}
+
+impl<F: Float> Generator<F> for RegressionCheck {
+    const NAME: &'static str = "regression check";
+
+    const SHORT_NAME: &'static str = "regression";
+
+    type WriteCtx = &'static str;
+
+    fn total_tests() -> u64 {
+        REGRESSIONS.len().try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        Self { iter: REGRESSIONS.iter() }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        s.write_str(ctx).unwrap();
+    }
+}
+
+impl Iterator for RegressionCheck {
+    type Item = &'static str;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next().copied()
+    }
+}
diff --git a/src/etc/test-float-parse/src/gen/subnorm.rs b/src/etc/test-float-parse/src/gen/subnorm.rs
new file mode 100644
index 00000000000..4fe3b90a3dd
--- /dev/null
+++ b/src/etc/test-float-parse/src/gen/subnorm.rs
@@ -0,0 +1,103 @@
+use std::cmp::min;
+use std::fmt::Write;
+use std::ops::RangeInclusive;
+
+use crate::{Float, Generator, Int};
+
+/// Spot check some edge cases for subnormals.
+pub struct SubnormEdgeCases<F: Float> {
+    cases: [F::Int; 6],
+    index: usize,
+}
+
+impl<F: Float> SubnormEdgeCases<F> {
+    /// Shorthand
+    const I1: F::Int = F::Int::ONE;
+
+    fn edge_cases() -> [F::Int; 6] {
+        // Comments use an 8-bit mantissa as a demo
+        [
+            // 0b00000001
+            Self::I1,
+            // 0b10000000
+            Self::I1 << (F::MAN_BITS - 1),
+            // 0b00001000
+            Self::I1 << ((F::MAN_BITS / 2) - 1),
+            // 0b00001111
+            Self::I1 << ((F::MAN_BITS / 2) - 1),
+            // 0b00001111
+            Self::I1 << ((F::MAN_BITS / 2) - 1),
+            // 0b11111111
+            F::MAN_MASK,
+        ]
+    }
+}
+
+impl<F: Float> Generator<F> for SubnormEdgeCases<F> {
+    const NAME: &'static str = "subnormal edge cases";
+    const SHORT_NAME: &'static str = "subnorm edge";
+
+    type WriteCtx = F;
+
+    fn new() -> Self {
+        Self { cases: Self::edge_cases(), index: 0 }
+    }
+
+    fn total_tests() -> u64 {
+        Self::edge_cases().len().try_into().unwrap()
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for SubnormEdgeCases<F> {
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let i = self.cases.get(self.index)?;
+        self.index += 1;
+
+        Some(F::from_bits(*i))
+    }
+}
+
+/// Test all subnormals up to `1 << 22`.
+pub struct SubnormComplete<F: Float> {
+    iter: RangeInclusive<F::Int>,
+}
+
+impl<F: Float> Generator<F> for SubnormComplete<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    const NAME: &'static str = "subnormal";
+    const SHORT_NAME: &'static str = "subnorm ";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        let iter = Self::new().iter;
+        (F::Int::ONE + *iter.end() - *iter.start()).try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        Self { iter: F::Int::ZERO..=min(F::Int::ONE << 22, F::MAN_BITS.try_into().unwrap()) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for SubnormComplete<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(F::from_bits(self.iter.next()?))
+    }
+}
diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs
index 9cbad5486b4..f36e3928d26 100644
--- a/src/etc/test-float-parse/src/lib.rs
+++ b/src/etc/test-float-parse/src/lib.rs
@@ -1,16 +1,526 @@
-use std::io;
-use std::io::prelude::*;
-use std::mem::transmute;
-
-// Nothing up my sleeve: Just (PI - 3) in base 16.
-#[allow(dead_code)]
-pub const SEED: [u32; 3] = [0x243f_6a88, 0x85a3_08d3, 0x1319_8a2e];
-
-pub fn validate(text: &str) {
-    let mut out = io::stdout();
-    let x: f64 = text.parse().unwrap();
-    let f64_bytes: u64 = unsafe { transmute(x) };
-    let x: f32 = text.parse().unwrap();
-    let f32_bytes: u32 = unsafe { transmute(x) };
-    writeln!(&mut out, "{:016x} {:08x} {}", f64_bytes, f32_bytes, text).unwrap();
+mod traits;
+mod ui;
+mod validate;
+
+use std::any::{type_name, TypeId};
+use std::cmp::min;
+use std::ops::RangeInclusive;
+use std::process::ExitCode;
+use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::{mpsc, OnceLock};
+use std::{fmt, time};
+
+use indicatif::{MultiProgress, ProgressBar};
+use rand::distributions::{Distribution, Standard};
+use rayon::prelude::*;
+use time::{Duration, Instant};
+use traits::{Float, Generator, Int};
+
+/// Test generators.
+mod gen {
+    pub mod exhaustive;
+    pub mod exponents;
+    pub mod fuzz;
+    pub mod integers;
+    pub mod long_fractions;
+    pub mod many_digits;
+    pub mod sparse;
+    pub mod spot_checks;
+    pub mod subnorm;
+}
+
+/// How many failures to exit after if unspecified.
+const DEFAULT_MAX_FAILURES: u64 = 20;
+
+/// Register exhaustive tests only for <= 32 bits. No more because it would take years.
+const MAX_BITS_FOR_EXHAUUSTIVE: u32 = 32;
+
+/// If there are more tests than this threashold, the test will be defered until after all
+/// others run (so as to avoid thread pool starvation). They also can be excluded with
+/// `--skip-huge`.
+const HUGE_TEST_CUTOFF: u64 = 5_000_000;
+
+/// Seed for tests that use a deterministic RNG.
+const SEED: [u8; 32] = *b"3.141592653589793238462643383279";
+
+/// Global configuration
+#[derive(Debug)]
+pub struct Config {
+    pub timeout: Duration,
+    /// Failures per test
+    pub max_failures: u64,
+    pub disable_max_failures: bool,
+    /// If `None`, the default will be used
+    pub fuzz_count: Option<u64>,
+    pub skip_huge: bool,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            timeout: Duration::from_secs(60 * 60 * 3),
+            max_failures: DEFAULT_MAX_FAILURES,
+            disable_max_failures: false,
+            fuzz_count: None,
+            skip_huge: false,
+        }
+    }
+}
+
+/// Collect, filter, and launch all tests.
+pub fn run(cfg: Config, include: &[String], exclude: &[String]) -> ExitCode {
+    // With default parallelism, the CPU doesn't saturate. We don't need to be nice to
+    // other processes, so do 1.5x to make sure we use all available resources.
+    let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2;
+    rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap();
+
+    let mut tests = register_tests(&cfg);
+    println!("registered");
+    let initial_tests: Vec<_> = tests.iter().map(|t| t.name.clone()).collect();
+
+    let unmatched: Vec<_> = include
+        .iter()
+        .chain(exclude.iter())
+        .filter(|filt| !tests.iter().any(|t| t.matches(filt)))
+        .collect();
+
+    assert!(
+        unmatched.is_empty(),
+        "filters were provided that have no matching tests: {unmatched:#?}"
+    );
+
+    tests.retain(|test| !exclude.iter().any(|exc| test.matches(exc)));
+
+    if cfg.skip_huge {
+        tests.retain(|test| !test.is_huge_test());
+    }
+
+    if !include.is_empty() {
+        tests.retain(|test| include.iter().any(|inc| test.matches(inc)));
+    }
+
+    for exc in initial_tests.iter().filter(|orig_name| !tests.iter().any(|t| t.name == **orig_name))
+    {
+        println!("Skipping test '{exc}'");
+    }
+
+    println!("launching");
+    let elapsed = launch_tests(&mut tests, &cfg);
+    ui::finish(&tests, elapsed, &cfg)
+}
+
+/// Enumerate tests to run but don't actaully run them.
+pub fn register_tests(cfg: &Config) -> Vec<TestInfo> {
+    let mut tests = Vec::new();
+
+    // Register normal generators for all floats.
+    register_float::<f32>(&mut tests, cfg);
+    register_float::<f64>(&mut tests, cfg);
+
+    tests.sort_unstable_by_key(|t| (t.float_name, t.gen_name));
+    for i in 0..(tests.len() - 1) {
+        if tests[i].gen_name == tests[i + 1].gen_name {
+            panic!("dupliate test name {}", tests[i].gen_name);
+        }
+    }
+
+    tests
+}
+
+/// Register all generators for a single float.
+fn register_float<F: Float>(tests: &mut Vec<TestInfo>, cfg: &Config)
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+    <F::Int as TryFrom<u128>>::Error: std::fmt::Debug,
+    Standard: Distribution<<F as traits::Float>::Int>,
+{
+    if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE {
+        // Only run exhaustive tests if there is a chance of completion.
+        TestInfo::register::<F, gen::exhaustive::Exhaustive<F>>(tests);
+    }
+
+    gen::fuzz::Fuzz::<F>::set_iterations(cfg.fuzz_count);
+
+    TestInfo::register::<F, gen::exponents::LargeExponents<F>>(tests);
+    TestInfo::register::<F, gen::exponents::SmallExponents<F>>(tests);
+    TestInfo::register::<F, gen::fuzz::Fuzz<F>>(tests);
+    TestInfo::register::<F, gen::integers::LargeInt<F>>(tests);
+    TestInfo::register::<F, gen::integers::SmallInt>(tests);
+    TestInfo::register::<F, gen::long_fractions::RepeatingDecimal>(tests);
+    TestInfo::register::<F, gen::many_digits::RandDigits<F>>(tests);
+    TestInfo::register::<F, gen::sparse::FewOnesFloat<F>>(tests);
+    TestInfo::register::<F, gen::sparse::FewOnesInt<F>>(tests);
+    TestInfo::register::<F, gen::spot_checks::RegressionCheck>(tests);
+    TestInfo::register::<F, gen::spot_checks::Special>(tests);
+    TestInfo::register::<F, gen::subnorm::SubnormComplete<F>>(tests);
+    TestInfo::register::<F, gen::subnorm::SubnormEdgeCases<F>>(tests);
+}
+
+/// Configuration for a single test.
+#[derive(Debug)]
+pub struct TestInfo {
+    pub name: String,
+    /// Tests are identified by the type ID of `(F, G)` (tuple of the float and generator type).
+    /// This gives an easy way to associate messages with tests.
+    id: TypeId,
+    float_name: &'static str,
+    gen_name: &'static str,
+    /// Name for display in the progress bar.
+    short_name: String,
+    total_tests: u64,
+    /// Function to launch this test.
+    launch: fn(&mpsc::Sender<Msg>, &TestInfo, &Config),
+    /// Progress bar to be updated.
+    pb: Option<ProgressBar>,
+    /// Once completed, this will be set.
+    completed: OnceLock<Completed>,
+}
+
+impl TestInfo {
+    /// Check if either the name or short name is a match, for filtering.
+    fn matches(&self, pat: &str) -> bool {
+        self.short_name.contains(pat) || self.name.contains(pat)
+    }
+
+    /// Create a `TestInfo` for a given float and generator, then add it to a list.
+    fn register<F: Float, G: Generator<F>>(v: &mut Vec<Self>) {
+        let f_name = type_name::<F>();
+        let gen_name = G::NAME;
+        let gen_short_name = G::SHORT_NAME;
+
+        let info = TestInfo {
+            id: TypeId::of::<(F, G)>(),
+            float_name: f_name,
+            gen_name,
+            pb: None,
+            name: format!("{f_name} {gen_name}"),
+            short_name: format!("{f_name} {gen_short_name}"),
+            launch: test_runner::<F, G>,
+            total_tests: G::total_tests(),
+            completed: OnceLock::new(),
+        };
+        v.push(info);
+    }
+
+    /// Pad the short name to a common width for progress bar use.
+    fn short_name_padded(&self) -> String {
+        format!("{:18}", self.short_name)
+    }
+
+    /// Create a progress bar for this test within a multiprogress bar.
+    fn register_pb(&mut self, mp: &MultiProgress, drop_bars: &mut Vec<ProgressBar>) {
+        self.pb = Some(ui::create_pb(mp, self.total_tests, &self.short_name_padded(), drop_bars));
+    }
+
+    /// When the test is finished, update progress bar messages and finalize.
+    fn finalize_pb(&self, c: &Completed) {
+        let pb = self.pb.as_ref().unwrap();
+        ui::finalize_pb(pb, &self.short_name_padded(), c);
+    }
+
+    /// True if this should be run after all others.
+    fn is_huge_test(&self) -> bool {
+        self.total_tests >= HUGE_TEST_CUTOFF
+    }
+}
+
+/// A message sent from test runner threads to the UI/log thread.
+#[derive(Clone, Debug)]
+struct Msg {
+    id: TypeId,
+    update: Update,
+}
+
+impl Msg {
+    /// Wrap an `Update` into a message for the specified type. We use the `TypeId` of `(F, G)` to
+    /// identify which test a message in the channel came from.
+    fn new<F: Float, G: Generator<F>>(u: Update) -> Self {
+        Self { id: TypeId::of::<(F, G)>(), update: u }
+    }
+
+    /// Get the matching test from a list. Panics if not found.
+    fn find_test<'a>(&self, tests: &'a [TestInfo]) -> &'a TestInfo {
+        tests.iter().find(|t| t.id == self.id).unwrap()
+    }
+
+    /// Update UI as needed for a single message received from the test runners.
+    fn handle(self, tests: &[TestInfo], mp: &MultiProgress) {
+        let test = self.find_test(tests);
+        let pb = test.pb.as_ref().unwrap();
+
+        match self.update {
+            Update::Started => {
+                mp.println(format!("Testing '{}'", test.name)).unwrap();
+            }
+            Update::Progress { executed, failures } => {
+                pb.set_message(format! {"{failures}"});
+                pb.set_position(executed);
+            }
+            Update::Failure { fail, input, float_res } => {
+                mp.println(format!(
+                    "Failure in '{}': {fail}. parsing '{input}'. Parsed as: {float_res}",
+                    test.name
+                ))
+                .unwrap();
+            }
+            Update::Completed(c) => {
+                test.finalize_pb(&c);
+
+                let prefix = match c.result {
+                    Ok(FinishedAll) => "Completed tests for",
+                    Err(EarlyExit::Timeout) => "Timed out",
+                    Err(EarlyExit::MaxFailures) => "Max failures reached for",
+                };
+
+                mp.println(format!(
+                    "{prefix} generator '{}' in {:?}. {} tests run, {} failures",
+                    test.name, c.elapsed, c.executed, c.failures
+                ))
+                .unwrap();
+                test.completed.set(c).unwrap();
+            }
+        };
+    }
+}
+
+/// Status sent with a message.
+#[derive(Clone, Debug)]
+enum Update {
+    /// Starting a new test runner.
+    Started,
+    /// Completed a out of b tests.
+    Progress { executed: u64, failures: u64 },
+    /// Received a failed test.
+    Failure {
+        fail: CheckFailure,
+        /// String for which parsing was attempted.
+        input: Box<str>,
+        /// The parsed & decomposed `FloatRes`, aleady stringified so we don't need generics here.
+        float_res: Box<str>,
+    },
+    /// Exited with an unexpected condition.
+    Completed(Completed),
+}
+
+/// Result of an input did not parsing successfully.
+#[derive(Clone, Debug)]
+enum CheckFailure {
+    /// Above the zero cutoff but got rounded to zero.
+    UnexpectedZero,
+    /// Below the infinity cutoff but got rounded to infinity.
+    UnexpectedInf,
+    /// Above the negative infinity cutoff but got rounded to negative infinity.
+    UnexpectedNegInf,
+    /// Got a `NaN` when none was expected.
+    UnexpectedNan,
+    /// Expected `NaN`, got none.
+    ExpectedNan,
+    /// Expected infinity, got finite.
+    ExpectedInf,
+    /// Expected negative infinity, got finite.
+    ExpectedNegInf,
+    /// The value exceeded its error tolerance.
+    InvalidReal {
+        /// Error from the expected value, as a float.
+        error_float: Option<f64>,
+        /// Error as a rational string (since it can't always be represented as a float).
+        error_str: Box<str>,
+        /// True if the error was caused by not rounding to even at the midpoint between
+        /// two representable values.
+        incorrect_midpoint_rounding: bool,
+    },
+}
+
+impl fmt::Display for CheckFailure {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            CheckFailure::UnexpectedZero => {
+                write!(f, "incorrectly rounded to 0 (expected nonzero)")
+            }
+            CheckFailure::UnexpectedInf => {
+                write!(f, "incorrectly rounded to +inf (expected finite)")
+            }
+            CheckFailure::UnexpectedNegInf => {
+                write!(f, "incorrectly rounded to -inf (expected finite)")
+            }
+            CheckFailure::UnexpectedNan => write!(f, "got a NaN where none was expected"),
+            CheckFailure::ExpectedNan => write!(f, "expected a NaN but did not get it"),
+            CheckFailure::ExpectedInf => write!(f, "expected +inf but did not get it"),
+            CheckFailure::ExpectedNegInf => write!(f, "expected -inf but did not get it"),
+            CheckFailure::InvalidReal { error_float, error_str, incorrect_midpoint_rounding } => {
+                if *incorrect_midpoint_rounding {
+                    write!(
+                        f,
+                        "midpoint between two representable values did not correctly \
+                        round to even; error: {error_str}"
+                    )?;
+                } else {
+                    write!(f, "real number did not parse correctly; error: {error_str}")?;
+                }
+
+                if let Some(float) = error_float {
+                    write!(f, " ({float})")?;
+                }
+                Ok(())
+            }
+        }
+    }
+}
+
+/// Information about a completed test generator.
+#[derive(Clone, Debug)]
+struct Completed {
+    /// Finished tests (both successful and failed).
+    executed: u64,
+    /// Failed tests.
+    failures: u64,
+    /// Extra exit information if unsuccessful.
+    result: Result<FinishedAll, EarlyExit>,
+    /// If there is something to warn about (e.g bad estimate), leave it here.
+    warning: Option<Box<str>>,
+    /// Total time to run the test.
+    elapsed: Duration,
+}
+
+/// Marker for completing all tests (used in `Result` types).
+#[derive(Clone, Debug)]
+struct FinishedAll;
+
+/// Reasons for exiting early.
+#[derive(Clone, Debug)]
+enum EarlyExit {
+    Timeout,
+    MaxFailures,
+}
+
+/// Run all tests in `tests`.
+///
+/// This launches a main thread that receives messages and handlees UI updates, and uses the
+/// rest of the thread pool to execute the tests.
+fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration {
+    // Run shorter tests first
+    tests.sort_unstable_by_key(|test| test.total_tests);
+
+    for test in tests.iter() {
+        println!("Launching test '{}'", test.name);
+    }
+
+    // Configure progress bars
+    let mut all_progress_bars = Vec::new();
+    let mp = MultiProgress::new();
+    mp.set_move_cursor(true);
+    for test in tests.iter_mut() {
+        test.register_pb(&mp, &mut all_progress_bars);
+    }
+
+    ui::set_panic_hook(all_progress_bars);
+
+    let (tx, rx) = mpsc::channel::<Msg>();
+    let start = Instant::now();
+
+    rayon::scope(|scope| {
+        // Thread that updates the UI
+        scope.spawn(|_scope| {
+            let rx = rx; // move rx
+
+            loop {
+                if tests.iter().all(|t| t.completed.get().is_some()) {
+                    break;
+                }
+
+                let msg = rx.recv().unwrap();
+                msg.handle(tests, &mp);
+            }
+
+            // All tests completed; finish things up
+            drop(mp);
+            assert_eq!(rx.try_recv().unwrap_err(), mpsc::TryRecvError::Empty);
+        });
+
+        // Don't let the thread pool be starved by huge tests. Run faster tests first in parallel,
+        // then parallelize only within the rest of the tests.
+        let (huge_tests, normal_tests): (Vec<_>, Vec<_>) =
+            tests.iter().partition(|t| t.is_huge_test());
+
+        // Run the actual tests
+        normal_tests.par_iter().for_each(|test| ((test.launch)(&tx, test, cfg)));
+
+        huge_tests.par_iter().for_each(|test| ((test.launch)(&tx, test, cfg)));
+    });
+
+    start.elapsed()
+}
+
+/// Test runer for a single generator.
+///
+/// This calls the generator's iterator multiple times (in parallel) and validates each output.
+fn test_runner<F: Float, G: Generator<F>>(tx: &mpsc::Sender<Msg>, _info: &TestInfo, cfg: &Config) {
+    tx.send(Msg::new::<F, G>(Update::Started)).unwrap();
+
+    let total = G::total_tests();
+    let gen = G::new();
+    let executed = AtomicU64::new(0);
+    let failures = AtomicU64::new(0);
+
+    let checks_per_update = min(total, 1000);
+    let started = Instant::now();
+
+    // Function to execute for a single test iteration.
+    let check_one = |buf: &mut String, ctx: G::WriteCtx| {
+        let executed = executed.fetch_add(1, Ordering::Relaxed);
+        buf.clear();
+        G::write_string(buf, ctx);
+
+        match validate::validate::<F>(buf) {
+            Ok(()) => (),
+            Err(e) => {
+                tx.send(Msg::new::<F, G>(e)).unwrap();
+                let f = failures.fetch_add(1, Ordering::Relaxed);
+                // End early if the limit is exceeded.
+                if f >= cfg.max_failures {
+                    return Err(EarlyExit::MaxFailures);
+                }
+            }
+        };
+
+        // Send periodic updates
+        if executed % checks_per_update == 0 {
+            let failures = failures.load(Ordering::Relaxed);
+
+            tx.send(Msg::new::<F, G>(Update::Progress { executed, failures })).unwrap();
+
+            if started.elapsed() > cfg.timeout {
+                return Err(EarlyExit::Timeout);
+            }
+        }
+
+        Ok(())
+    };
+
+    // Run the test iterations in parallel. Each thread gets a string buffer to write
+    // its check values to.
+    let res = gen.par_bridge().try_for_each_init(|| String::with_capacity(100), check_one);
+
+    let elapsed = started.elapsed();
+    let executed = executed.into_inner();
+    let failures = failures.into_inner();
+
+    // Warn about bad estimates if relevant.
+    let warning = if executed != total && res.is_ok() {
+        let msg = format!("executed tests != estimated ({executed} != {total}) for {}", G::NAME);
+
+        Some(msg.into())
+    } else {
+        None
+    };
+
+    let result = res.map(|()| FinishedAll);
+    tx.send(Msg::new::<F, G>(Update::Completed(Completed {
+        executed,
+        failures,
+        result,
+        warning,
+        elapsed,
+    })))
+    .unwrap();
 }
diff --git a/src/etc/test-float-parse/src/main.rs b/src/etc/test-float-parse/src/main.rs
new file mode 100644
index 00000000000..9c6cad7324f
--- /dev/null
+++ b/src/etc/test-float-parse/src/main.rs
@@ -0,0 +1,129 @@
+use std::process::ExitCode;
+use std::time::Duration;
+
+use test_float_parse as tfp;
+
+static HELP: &str = r#"Usage:
+
+  ./test-float-parse [--timeout x] [--exclude x] [--max-failures x] [INCLUDE ...]
+  ./test-float-parse [--fuzz-count x] [INCLUDE ...]
+  ./test-float-parse [--skip-huge] [INCLUDE ...]
+  ./test-float-parse --list
+
+Args:
+
+  INCLUDE                  Include only tests with names containing these
+                           strings. If this argument is not specified, all tests
+                           are run.
+  --timeout N              Exit after this amount of time (in seconds).
+  --exclude FILTER         Skip tests containing this string. May be specified
+                           more than once.
+  --list                   List available tests.
+  --max-failures N         Limit to N failures per test. Defaults to 20. Pass
+                           "--max-failures none" to remove this limit.
+  --fuzz-count N           Run the fuzzer with N iterations. Only has an effect
+                           if fuzz tests are enabled. Pass `--fuzz-count none`
+                           to remove this limit.
+  --skip-huge              Skip tests that run for a long time.
+  --all                    Reset previous `--exclude`, `--skip-huge`, and
+                           `INCLUDE` arguments (useful for running all tests
+                           via `./x`).
+"#;
+
+enum ArgMode {
+    Any,
+    Timeout,
+    Exclude,
+    FuzzCount,
+    MaxFailures,
+}
+
+fn main() -> ExitCode {
+    if cfg!(debug_assertions) {
+        println!(
+            "WARNING: running in debug mode. Release mode is recommended to reduce test duration."
+        );
+        std::thread::sleep(Duration::from_secs(2));
+    }
+
+    let args: Vec<_> = std::env::args().skip(1).collect();
+    if args.iter().any(|arg| arg == "--help" || arg == "-h") {
+        println!("{HELP}");
+        return ExitCode::SUCCESS;
+    }
+
+    if args.iter().any(|arg| arg == "--list") {
+        let tests = tfp::register_tests(&tfp::Config::default());
+        println!("Available tests:");
+        for t in tests {
+            println!("{}", t.name);
+        }
+
+        return ExitCode::SUCCESS;
+    }
+
+    let (cfg, include, exclude) = parse_args(args);
+
+    tfp::run(cfg, &include, &exclude)
+}
+
+/// Simple command argument parser
+fn parse_args(args: Vec<String>) -> (tfp::Config, Vec<String>, Vec<String>) {
+    let mut cfg = tfp::Config::default();
+
+    let mut mode = ArgMode::Any;
+    let mut include = Vec::new();
+    let mut exclude = Vec::new();
+
+    for arg in args {
+        mode = match mode {
+            ArgMode::Any if arg == "--timeout" => ArgMode::Timeout,
+            ArgMode::Any if arg == "--exclude" => ArgMode::Exclude,
+            ArgMode::Any if arg == "--max-failures" => ArgMode::MaxFailures,
+            ArgMode::Any if arg == "--fuzz-count" => ArgMode::FuzzCount,
+            ArgMode::Any if arg == "--skip-huge" => {
+                cfg.skip_huge = true;
+                ArgMode::Any
+            }
+            ArgMode::Any if arg == "--all" => {
+                cfg.skip_huge = false;
+                include.clear();
+                exclude.clear();
+                ArgMode::Any
+            }
+            ArgMode::Any if arg.starts_with('-') => {
+                panic!("Unknown argument {arg}. Usage:\n{HELP}")
+            }
+            ArgMode::Any => {
+                include.push(arg);
+                ArgMode::Any
+            }
+            ArgMode::Timeout => {
+                cfg.timeout = Duration::from_secs(arg.parse().unwrap());
+                ArgMode::Any
+            }
+            ArgMode::MaxFailures => {
+                if arg == "none" {
+                    cfg.disable_max_failures = true;
+                } else {
+                    cfg.max_failures = arg.parse().unwrap();
+                }
+                ArgMode::Any
+            }
+            ArgMode::FuzzCount => {
+                if arg == "none" {
+                    cfg.fuzz_count = Some(u64::MAX);
+                } else {
+                    cfg.fuzz_count = Some(arg.parse().unwrap());
+                }
+                ArgMode::Any
+            }
+            ArgMode::Exclude => {
+                exclude.push(arg);
+                ArgMode::Any
+            }
+        }
+    }
+
+    (cfg, include, exclude)
+}
diff --git a/src/etc/test-float-parse/src/traits.rs b/src/etc/test-float-parse/src/traits.rs
new file mode 100644
index 00000000000..dc009ea235f
--- /dev/null
+++ b/src/etc/test-float-parse/src/traits.rs
@@ -0,0 +1,202 @@
+//! Interfaces used throughout this crate.
+
+use std::str::FromStr;
+use std::{fmt, ops};
+
+use num::bigint::ToBigInt;
+use num::Integer;
+
+use crate::validate::Constants;
+
+/// Integer types.
+#[allow(dead_code)] // Some functions only used for testing
+pub trait Int:
+    Clone
+    + Copy
+    + fmt::Debug
+    + fmt::Display
+    + fmt::LowerHex
+    + ops::Add<Output = Self>
+    + ops::Sub<Output = Self>
+    + ops::Shl<u32, Output = Self>
+    + ops::Shr<u32, Output = Self>
+    + ops::BitAnd<Output = Self>
+    + ops::BitOr<Output = Self>
+    + ops::Not<Output = Self>
+    + ops::AddAssign
+    + ops::BitAndAssign
+    + ops::BitOrAssign
+    + From<u8>
+    + TryFrom<i8>
+    + TryFrom<u32, Error: fmt::Debug>
+    + TryFrom<u64, Error: fmt::Debug>
+    + TryFrom<u128, Error: fmt::Debug>
+    + TryInto<u64, Error: fmt::Debug>
+    + TryInto<u32, Error: fmt::Debug>
+    + ToBigInt
+    + PartialOrd
+    + Integer
+    + Send
+    + 'static
+{
+    type Signed: Int;
+    type Bytes: Default + AsMut<[u8]>;
+
+    const BITS: u32;
+    const ZERO: Self;
+    const ONE: Self;
+    const MAX: Self;
+
+    fn to_signed(self) -> Self::Signed;
+    fn wrapping_neg(self) -> Self;
+    fn trailing_zeros(self) -> u32;
+
+    fn hex(self) -> String {
+        format!("{self:x}")
+    }
+}
+
+macro_rules! impl_int {
+    ($($uty:ty, $sty:ty);+) => {
+        $(
+            impl Int for $uty {
+                type Signed = $sty;
+                type Bytes = [u8; Self::BITS as usize / 8];
+                const BITS: u32 = Self::BITS;
+                const ZERO: Self = 0;
+                const ONE: Self = 1;
+                const MAX: Self = Self::MAX;
+                fn to_signed(self) -> Self::Signed {
+                    self.try_into().unwrap()
+                }
+                fn wrapping_neg(self) -> Self {
+                    self.wrapping_neg()
+                }
+                fn trailing_zeros(self) -> u32 {
+                    self.trailing_zeros()
+                }
+            }
+
+            impl Int for $sty {
+                type Signed = Self;
+                type Bytes = [u8; Self::BITS as usize / 8];
+                const BITS: u32 = Self::BITS;
+                const ZERO: Self = 0;
+                const ONE: Self = 1;
+                const MAX: Self = Self::MAX;
+                fn to_signed(self) -> Self::Signed {
+                    self
+                }
+                fn wrapping_neg(self) -> Self {
+                    self.wrapping_neg()
+                }
+                fn trailing_zeros(self) -> u32 {
+                    self.trailing_zeros()
+                }
+            }
+        )+
+    }
+}
+
+impl_int!(u32, i32; u64, i64);
+
+/// Floating point types.
+pub trait Float:
+    Copy + fmt::Debug + fmt::LowerExp + FromStr<Err: fmt::Display> + Sized + Send + 'static
+{
+    /// Unsigned integer of same width
+    type Int: Int<Signed = Self::SInt>;
+    type SInt: Int;
+
+    /// Total bits
+    const BITS: u32;
+
+    /// (Stored) bits in the mantissa)
+    const MAN_BITS: u32;
+
+    /// Bits in the exponent
+    const EXP_BITS: u32 = Self::BITS - Self::MAN_BITS - 1;
+
+    /// A saturated exponent (all ones)
+    const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1;
+
+    /// The exponent bias, also its maximum value
+    const EXP_BIAS: u32 = Self::EXP_SAT >> 1;
+
+    const MAN_MASK: Self::Int;
+    const SIGN_MASK: Self::Int;
+
+    fn from_bits(i: Self::Int) -> Self;
+    fn to_bits(self) -> Self::Int;
+
+    /// Rational constants associated with this float type.
+    fn constants() -> &'static Constants;
+
+    fn is_sign_negative(self) -> bool {
+        (self.to_bits() & Self::SIGN_MASK) > Self::Int::ZERO
+    }
+
+    /// Exponent without adjustment for bias.
+    fn exponent(self) -> u32 {
+        ((self.to_bits() >> Self::MAN_BITS) & Self::EXP_SAT.try_into().unwrap()).try_into().unwrap()
+    }
+
+    fn mantissa(self) -> Self::Int {
+        self.to_bits() & Self::MAN_MASK
+    }
+}
+
+macro_rules! impl_float {
+    ($($fty:ty, $ity:ty, $bits:literal);+) => {
+        $(
+            impl Float for $fty {
+                type Int = $ity;
+                type SInt = <Self::Int as Int>::Signed;
+                const BITS: u32 = $bits;
+                const MAN_BITS: u32 = Self::MANTISSA_DIGITS - 1;
+                const MAN_MASK: Self::Int = (Self::Int::ONE << Self::MAN_BITS) - Self::Int::ONE;
+                const SIGN_MASK: Self::Int = Self::Int::ONE << (Self::BITS-1);
+                fn from_bits(i: Self::Int) -> Self { Self::from_bits(i) }
+                fn to_bits(self) -> Self::Int { self.to_bits() }
+                fn constants() -> &'static Constants {
+                    use std::sync::LazyLock;
+                    static CONSTANTS: LazyLock<Constants> = LazyLock::new(Constants::new::<$fty>);
+                    &CONSTANTS
+                }
+            }
+        )+
+    }
+}
+
+impl_float!(f32, u32, 32; f64, u64, 64);
+
+/// A test generator. Should provide an iterator that produces unique patterns to parse.
+///
+/// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to
+/// write the string at a later step. This is done separately so that we can reuse string
+/// allocations (which otherwise turn out to be a pretty expensive part of these tests).
+pub trait Generator<F: Float>: Iterator<Item = Self::WriteCtx> + Send + 'static {
+    /// Full display and filtering name
+    const NAME: &'static str;
+
+    /// Name for display with the progress bar
+    const SHORT_NAME: &'static str;
+
+    /// The context needed to create a test string.
+    type WriteCtx: Send;
+
+    /// Number of tests that will be run.
+    fn total_tests() -> u64;
+
+    /// Constructor for this test generator.
+    fn new() -> Self;
+
+    /// Create a test string given write context, which was produced as a step from the iterator.
+    ///
+    /// `s` will be provided empty.
+    fn write_string(s: &mut String, ctx: Self::WriteCtx);
+}
+
+/// For tests that use iterator combinators, it is easier to just to box the iterator than trying
+/// to specify its type. This is a shorthand for the usual type.
+pub type BoxGenIter<This, F> = Box<dyn Iterator<Item = <This as Generator<F>>::WriteCtx> + Send>;
diff --git a/src/etc/test-float-parse/src/ui.rs b/src/etc/test-float-parse/src/ui.rs
new file mode 100644
index 00000000000..f333bd4a55d
--- /dev/null
+++ b/src/etc/test-float-parse/src/ui.rs
@@ -0,0 +1,132 @@
+//! Progress bars and such.
+
+use std::io::{self, Write};
+use std::process::ExitCode;
+use std::time::Duration;
+
+use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
+
+use crate::{Completed, Config, EarlyExit, FinishedAll, TestInfo};
+
+/// Templates for progress bars.
+const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME ({pos}/{len}, {msg} f, {per_sec}, eta {eta})";
+const PB_TEMPLATE_FINAL: &str =
+    "[{elapsed:3} {percent:3}%] NAME ({pos}/{len}, {msg:.COLOR}, {per_sec}, {elapsed_precise})";
+
+/// Create a new progress bar within a multiprogress bar.
+pub fn create_pb(
+    mp: &MultiProgress,
+    total_tests: u64,
+    short_name_padded: &str,
+    all_bars: &mut Vec<ProgressBar>,
+) -> ProgressBar {
+    let pb = mp.add(ProgressBar::new(total_tests));
+    let pb_style = ProgressStyle::with_template(&PB_TEMPLATE.replace("NAME", short_name_padded))
+        .unwrap()
+        .progress_chars("##-");
+
+    pb.set_style(pb_style.clone());
+    pb.set_message("0");
+    all_bars.push(pb.clone());
+    pb
+}
+
+/// Removes the status bar and replace it with a message.
+pub fn finalize_pb(pb: &ProgressBar, short_name_padded: &str, c: &Completed) {
+    let f = c.failures;
+
+    // Use a tuple so we can use colors
+    let (color, msg, finish_pb): (&str, String, fn(&ProgressBar, String)) = match &c.result {
+        Ok(FinishedAll) if f > 0 => {
+            ("red", format!("{f} f (finished with errors)",), ProgressBar::finish_with_message)
+        }
+        Ok(FinishedAll) => {
+            ("green", format!("{f} f (finished successfully)",), ProgressBar::finish_with_message)
+        }
+        Err(EarlyExit::Timeout) => {
+            ("red", format!("{f} f (timed out)"), ProgressBar::abandon_with_message)
+        }
+        Err(EarlyExit::MaxFailures) => {
+            ("red", format!("{f} f (failure limit)"), ProgressBar::abandon_with_message)
+        }
+    };
+
+    let pb_style = ProgressStyle::with_template(
+        &PB_TEMPLATE_FINAL.replace("NAME", short_name_padded).replace("COLOR", color),
+    )
+    .unwrap();
+
+    pb.set_style(pb_style);
+    finish_pb(pb, msg);
+}
+
+/// Print final messages after all tests are complete.
+pub fn finish(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> ExitCode {
+    println!("\n\nResults:");
+
+    let mut failed_generators = 0;
+    let mut stopped_generators = 0;
+
+    for t in tests {
+        let Completed { executed, failures, elapsed, warning, result } = t.completed.get().unwrap();
+
+        let stat = if result.is_err() {
+            stopped_generators += 1;
+            "STOPPED"
+        } else if *failures > 0 {
+            failed_generators += 1;
+            "FAILURE"
+        } else {
+            "SUCCESS"
+        };
+
+        println!(
+            "    {stat} for generator '{name}'. {passed}/{executed} passed in {elapsed:?}",
+            name = t.name,
+            passed = executed - failures,
+        );
+
+        if let Some(warning) = warning {
+            println!("      warning: {warning}");
+        }
+
+        match result {
+            Ok(FinishedAll) => (),
+            Err(EarlyExit::Timeout) => {
+                println!("      exited early; exceded {:?} timeout", cfg.timeout)
+            }
+            Err(EarlyExit::MaxFailures) => {
+                println!("      exited early; exceeded {:?} max failures", cfg.max_failures)
+            }
+        }
+    }
+
+    println!(
+        "{passed}/{} tests succeeded in {total_elapsed:?} ({passed} passed, {} failed, {} stopped)",
+        tests.len(),
+        failed_generators,
+        stopped_generators,
+        passed = tests.len() - failed_generators - stopped_generators,
+    );
+
+    if failed_generators > 0 || stopped_generators > 0 {
+        ExitCode::FAILURE
+    } else {
+        ExitCode::SUCCESS
+    }
+}
+
+/// indicatif likes to eat panic messages. This workaround isn't ideal, but it improves things.
+/// <https://github.com/console-rs/indicatif/issues/121>.
+pub fn set_panic_hook(drop_bars: Vec<ProgressBar>) {
+    let hook = std::panic::take_hook();
+    std::panic::set_hook(Box::new(move |info| {
+        for bar in &drop_bars {
+            bar.abandon();
+            println!();
+            io::stdout().flush().unwrap();
+            io::stderr().flush().unwrap();
+        }
+        hook(info);
+    }));
+}
diff --git a/src/etc/test-float-parse/src/validate.rs b/src/etc/test-float-parse/src/validate.rs
new file mode 100644
index 00000000000..1eb3699cfb9
--- /dev/null
+++ b/src/etc/test-float-parse/src/validate.rs
@@ -0,0 +1,364 @@
+//! Everything related to verifying that parsed outputs are correct.
+
+use std::any::type_name;
+use std::collections::BTreeMap;
+use std::ops::RangeInclusive;
+use std::str::FromStr;
+use std::sync::LazyLock;
+
+use num::bigint::ToBigInt;
+use num::{BigInt, BigRational, FromPrimitive, Signed, ToPrimitive};
+
+use crate::{CheckFailure, Float, Int, Update};
+
+/// Powers of two that we store for constants. Account for binary128 which has a 15-bit exponent.
+const POWERS_OF_TWO_RANGE: RangeInclusive<i32> = (-(2 << 15))..=(2 << 15);
+
+/// Powers of ten that we cache. Account for binary128, which can fit +4932/-4931
+const POWERS_OF_TEN_RANGE: RangeInclusive<i32> = -5_000..=5_000;
+
+/// Cached powers of 10 so we can look them up rather than recreating.
+static POWERS_OF_TEN: LazyLock<BTreeMap<i32, BigRational>> = LazyLock::new(|| {
+    POWERS_OF_TEN_RANGE.map(|exp| (exp, BigRational::from_u32(10).unwrap().pow(exp))).collect()
+});
+
+/// Rational property-related constants for a specific float type.
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct Constants {
+    /// The minimum positive value (a subnormal).
+    min_subnormal: BigRational,
+    /// The maximum possible finite value.
+    max: BigRational,
+    /// Cutoff between rounding to zero and rounding to the minimum value (min subnormal).
+    zero_cutoff: BigRational,
+    /// Cutoff between rounding to the max value and rounding to infinity.
+    inf_cutoff: BigRational,
+    /// Opposite of `inf_cutoff`
+    neg_inf_cutoff: BigRational,
+    /// The powers of two for all relevant integers.
+    powers_of_two: BTreeMap<i32, BigRational>,
+    /// Half of each power of two. ULP = "unit in last position".
+    ///
+    /// This is a mapping from integers to half the precision available at that exponent. In other
+    /// words, `0.5 * 2^n` = `2^(n-1)`, which is half the distance between `m * 2^n` and
+    /// `(m + 1) * 2^n`, m ∈ ℤ.
+    ///
+    /// So, this is the maximum error from a real number to its floating point representation,
+    /// assuming the float type can represent the exponent.
+    half_ulp: BTreeMap<i32, BigRational>,
+    /// Handy to have around so we don't need to reallocate for it
+    two: BigInt,
+}
+
+impl Constants {
+    pub fn new<F: Float>() -> Self {
+        let two_int = &BigInt::from_u32(2).unwrap();
+        let two = &BigRational::from_integer(2.into());
+
+        // The minimum subnormal (aka minimum positive) value. Most negative power of two is the
+        // minimum exponent (bias - 1) plus the extra from shifting within the mantissa bits.
+        let min_subnormal = two.pow(-(F::EXP_BIAS + F::MAN_BITS - 1).to_signed());
+
+        // The maximum value is the maximum exponent with a fully saturated mantissa. This
+        // is easiest to calculate by evaluating what the next value up would be if representable
+        // (zeroed mantissa, exponent increments by one, i.e. `2^(bias + 1)`), and subtracting
+        // a single LSB (`2 ^ (-mantissa_bits)`).
+        let max = (two - two.pow(-F::MAN_BITS.to_signed())) * (two.pow(F::EXP_BIAS.to_signed()));
+        let zero_cutoff = &min_subnormal / two_int;
+
+        let inf_cutoff = &max + two_int.pow(F::EXP_BIAS - F::MAN_BITS - 1);
+        let neg_inf_cutoff = -&inf_cutoff;
+
+        let powers_of_two: BTreeMap<i32, _> =
+            (POWERS_OF_TWO_RANGE).map(|n| (n, two.pow(n))).collect();
+        let mut half_ulp = powers_of_two.clone();
+        half_ulp.iter_mut().for_each(|(_k, v)| *v = &*v / two_int);
+
+        Self {
+            min_subnormal,
+            max,
+            zero_cutoff,
+            inf_cutoff,
+            neg_inf_cutoff,
+            powers_of_two,
+            half_ulp,
+            two: two_int.clone(),
+        }
+    }
+}
+
+/// Validate that a string parses correctly
+pub fn validate<F: Float>(input: &str) -> Result<(), Update> {
+    let parsed: F = input
+        .parse()
+        .unwrap_or_else(|e| panic!("parsing failed for {}: {e}. Input: {input}", type_name::<F>()));
+
+    // Parsed float, decoded into significand and exponent
+    let decoded = decode(parsed);
+
+    // Float parsed separately into a rational
+    let rational = Rational::parse(input);
+
+    // Verify that the values match
+    decoded.check(rational, input)
+}
+
+/// The result of parsing a string to a float type.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum FloatRes<F: Float> {
+    Inf,
+    NegInf,
+    Zero,
+    Nan,
+    /// A real number with significand and exponent. Value is `sig * 2 ^ exp`.
+    Real {
+        sig: F::SInt,
+        exp: i32,
+    },
+}
+
+impl<F: Float> FloatRes<F> {
+    /// Given a known exact rational, check that this representation is accurate within the
+    /// limits of the float representation. If not, construct a failure `Update` to send.
+    fn check(self, expected: Rational, input: &str) -> Result<(), Update> {
+        let consts = F::constants();
+        // let bool_helper = |cond: bool, err| cond.then_some(()).ok_or(err);
+
+        let res = match (expected, self) {
+            // Easy correct cases
+            (Rational::Inf, FloatRes::Inf)
+            | (Rational::NegInf, FloatRes::NegInf)
+            | (Rational::Nan, FloatRes::Nan) => Ok(()),
+
+            // Easy incorrect cases
+            (
+                Rational::Inf,
+                FloatRes::NegInf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. },
+            ) => Err(CheckFailure::ExpectedInf),
+            (
+                Rational::NegInf,
+                FloatRes::Inf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. },
+            ) => Err(CheckFailure::ExpectedNegInf),
+            (
+                Rational::Nan,
+                FloatRes::Inf | FloatRes::NegInf | FloatRes::Zero | FloatRes::Real { .. },
+            ) => Err(CheckFailure::ExpectedNan),
+            (Rational::Finite(_), FloatRes::Nan) => Err(CheckFailure::UnexpectedNan),
+
+            // Cases near limits
+            (Rational::Finite(r), FloatRes::Zero) => {
+                if r <= consts.zero_cutoff {
+                    Ok(())
+                } else {
+                    Err(CheckFailure::UnexpectedZero)
+                }
+            }
+            (Rational::Finite(r), FloatRes::Inf) => {
+                if r >= consts.inf_cutoff {
+                    Ok(())
+                } else {
+                    Err(CheckFailure::UnexpectedInf)
+                }
+            }
+            (Rational::Finite(r), FloatRes::NegInf) => {
+                if r <= consts.neg_inf_cutoff {
+                    Ok(())
+                } else {
+                    Err(CheckFailure::UnexpectedNegInf)
+                }
+            }
+
+            // Actual numbers
+            (Rational::Finite(r), FloatRes::Real { sig, exp }) => Self::validate_real(r, sig, exp),
+        };
+
+        res.map_err(|fail| Update::Failure {
+            fail,
+            input: input.into(),
+            float_res: format!("{self:?}").into(),
+        })
+    }
+
+    /// Check that `sig * 2^exp` is the same as `rational`, within the float's error margin.
+    fn validate_real(rational: BigRational, sig: F::SInt, exp: i32) -> Result<(), CheckFailure> {
+        let consts = F::constants();
+
+        // `2^exp`. Use cached powers of two to be faster.
+        let two_exp = consts
+            .powers_of_two
+            .get(&exp)
+            .unwrap_or_else(|| panic!("missing exponent {exp} for {}", type_name::<F>()));
+
+        // Rational from the parsed value, `sig * 2^exp`
+        let parsed_rational = two_exp * sig.to_bigint().unwrap();
+        let error = (parsed_rational - &rational).abs();
+
+        // Determine acceptable error at this exponent, which is halfway between this value
+        // (`sig * 2^exp`) and the next value up (`(sig+1) * 2^exp`).
+        let half_ulp = consts.half_ulp.get(&exp).unwrap();
+
+        // If we are within one error value (but not equal) then we rounded correctly.
+        if &error < half_ulp {
+            return Ok(());
+        }
+
+        // For values where we are exactly between two representable values, meaning that the error
+        // is exactly one half of the precision at that exponent, we need to round to an even
+        // binary value (i.e. mantissa ends in 0).
+        let incorrect_midpoint_rounding = if &error == half_ulp {
+            if sig & F::SInt::ONE == F::SInt::ZERO {
+                return Ok(());
+            }
+
+            // We rounded to odd rather than even; failing based on midpoint rounding.
+            true
+        } else {
+            // We are out of spec for some other reason.
+            false
+        };
+
+        let one_ulp = consts.half_ulp.get(&(exp + 1)).unwrap();
+        assert_eq!(one_ulp, &(half_ulp * &consts.two), "ULP values are incorrect");
+
+        let relative_error = error / one_ulp;
+
+        Err(CheckFailure::InvalidReal {
+            error_float: relative_error.to_f64(),
+            error_str: relative_error.to_string().into(),
+            incorrect_midpoint_rounding,
+        })
+    }
+
+    /// Remove trailing zeros in the significand and adjust the exponent
+    #[cfg(test)]
+    fn normalize(self) -> Self {
+        use std::cmp::min;
+
+        match self {
+            Self::Real { sig, exp } => {
+                // If there are trailing zeroes, remove them and increment the exponent instead
+                let shift = min(sig.trailing_zeros(), exp.wrapping_neg().try_into().unwrap());
+                Self::Real { sig: sig >> shift, exp: exp + i32::try_from(shift).unwrap() }
+            }
+            _ => self,
+        }
+    }
+}
+
+/// Decompose a float into its integral components. This includes the implicit bit.
+///
+/// If `allow_nan` is `false`, panic if `NaN` values are reached.
+fn decode<F: Float>(f: F) -> FloatRes<F> {
+    let ione = F::SInt::ONE;
+    let izero = F::SInt::ZERO;
+
+    let mut exponent_biased = f.exponent();
+    let mut mantissa = f.mantissa().to_signed();
+
+    if exponent_biased == 0 {
+        if mantissa == izero {
+            return FloatRes::Zero;
+        }
+
+        exponent_biased += 1;
+    } else if exponent_biased == F::EXP_SAT {
+        if mantissa != izero {
+            return FloatRes::Nan;
+        }
+
+        if f.is_sign_negative() {
+            return FloatRes::NegInf;
+        }
+
+        return FloatRes::Inf;
+    } else {
+        // Set implicit bit
+        mantissa |= ione << F::MAN_BITS;
+    }
+
+    let mut exponent = i32::try_from(exponent_biased).unwrap();
+
+    // Adjust for bias and the rnage of the mantissa
+    exponent -= i32::try_from(F::EXP_BIAS + F::MAN_BITS).unwrap();
+
+    if f.is_sign_negative() {
+        mantissa = mantissa.wrapping_neg();
+    }
+
+    FloatRes::Real { sig: mantissa, exp: exponent }
+}
+
+/// A rational or its unrepresentable values.
+#[derive(Clone, Debug, PartialEq)]
+enum Rational {
+    Inf,
+    NegInf,
+    Nan,
+    Finite(BigRational),
+}
+
+impl Rational {
+    /// Turn a string into a rational. `None` if `NaN`.
+    fn parse(s: &str) -> Rational {
+        let mut s = s; // lifetime rules
+
+        if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("nan")
+            || s.eq_ignore_ascii_case("-nan")
+        {
+            return Rational::Nan;
+        }
+
+        if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("inf") {
+            return Rational::Inf;
+        }
+
+        if s.eq_ignore_ascii_case("-inf") {
+            return Rational::NegInf;
+        }
+
+        // Fast path; no decimals or exponents ot parse
+        if s.bytes().all(|b| b.is_ascii_digit() || b == b'-') {
+            return Rational::Finite(BigRational::from_str(s).unwrap());
+        }
+
+        let mut ten_exp: i32 = 0;
+
+        // Remove and handle e.g. `e-4`, `e+10`, `e5` suffixes
+        if let Some(pos) = s.bytes().position(|b| b == b'e' || b == b'E') {
+            let (dec, exp) = s.split_at(pos);
+            s = dec;
+            ten_exp = exp[1..].parse().unwrap();
+        }
+
+        // Remove the decimal and instead change our exponent
+        // E.g. "12.3456" becomes "123456 * 10^-4"
+        let mut s_owned;
+        if let Some(pos) = s.bytes().position(|b| b == b'.') {
+            ten_exp = ten_exp.checked_sub((s.len() - pos - 1).try_into().unwrap()).unwrap();
+            s_owned = s.to_owned();
+            s_owned.remove(pos);
+            s = &s_owned;
+        }
+
+        // let pow = BigRational::from_u32(10).unwrap().pow(ten_exp);
+        let pow =
+            POWERS_OF_TEN.get(&ten_exp).unwrap_or_else(|| panic!("missing power of ten {ten_exp}"));
+        let r = pow
+            * BigInt::from_str(s)
+                .unwrap_or_else(|e| panic!("`BigInt::from_str(\"{s}\")` failed with {e}"));
+        Rational::Finite(r)
+    }
+
+    #[cfg(test)]
+    fn expect_finite(self) -> BigRational {
+        let Self::Finite(r) = self else {
+            panic!("got non rational: {self:?}");
+        };
+
+        r
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/etc/test-float-parse/src/validate/tests.rs b/src/etc/test-float-parse/src/validate/tests.rs
new file mode 100644
index 00000000000..ab0e7d8a7ba
--- /dev/null
+++ b/src/etc/test-float-parse/src/validate/tests.rs
@@ -0,0 +1,149 @@
+use num::ToPrimitive;
+
+use super::*;
+
+#[test]
+fn test_parse_rational() {
+    assert_eq!(Rational::parse("1234").expect_finite(), BigRational::new(1234.into(), 1.into()));
+    assert_eq!(
+        Rational::parse("-1234").expect_finite(),
+        BigRational::new((-1234).into(), 1.into())
+    );
+    assert_eq!(Rational::parse("1e+6").expect_finite(), BigRational::new(1000000.into(), 1.into()));
+    assert_eq!(Rational::parse("1e-6").expect_finite(), BigRational::new(1.into(), 1000000.into()));
+    assert_eq!(
+        Rational::parse("10.4e6").expect_finite(),
+        BigRational::new(10400000.into(), 1.into())
+    );
+    assert_eq!(
+        Rational::parse("10.4e+6").expect_finite(),
+        BigRational::new(10400000.into(), 1.into())
+    );
+    assert_eq!(
+        Rational::parse("10.4e-6").expect_finite(),
+        BigRational::new(13.into(), 1250000.into())
+    );
+    assert_eq!(
+        Rational::parse("10.4243566462342456234124").expect_finite(),
+        BigRational::new(104243566462342456234124_i128.into(), 10000000000000000000000_i128.into())
+    );
+    assert_eq!(Rational::parse("inf"), Rational::Inf);
+    assert_eq!(Rational::parse("+inf"), Rational::Inf);
+    assert_eq!(Rational::parse("-inf"), Rational::NegInf);
+    assert_eq!(Rational::parse("NaN"), Rational::Nan);
+}
+
+#[test]
+fn test_decode() {
+    assert_eq!(decode(0f32), FloatRes::Zero);
+    assert_eq!(decode(f32::INFINITY), FloatRes::Inf);
+    assert_eq!(decode(f32::NEG_INFINITY), FloatRes::NegInf);
+    assert_eq!(decode(1.0f32).normalize(), FloatRes::Real { sig: 1, exp: 0 });
+    assert_eq!(decode(-1.0f32).normalize(), FloatRes::Real { sig: -1, exp: 0 });
+    assert_eq!(decode(100.0f32).normalize(), FloatRes::Real { sig: 100, exp: 0 });
+    assert_eq!(decode(100.5f32).normalize(), FloatRes::Real { sig: 201, exp: -1 });
+    assert_eq!(decode(-4.004f32).normalize(), FloatRes::Real { sig: -8396997, exp: -21 });
+    assert_eq!(decode(0.0004f32).normalize(), FloatRes::Real { sig: 13743895, exp: -35 });
+    assert_eq!(decode(f32::from_bits(0x1)).normalize(), FloatRes::Real { sig: 1, exp: -149 });
+}
+
+#[test]
+fn test_validate() {
+    validate::<f32>("0").unwrap();
+    validate::<f32>("-0").unwrap();
+    validate::<f32>("1").unwrap();
+    validate::<f32>("-1").unwrap();
+    validate::<f32>("1.1").unwrap();
+    validate::<f32>("-1.1").unwrap();
+    validate::<f32>("1e10").unwrap();
+    validate::<f32>("1e1000").unwrap();
+    validate::<f32>("-1e1000").unwrap();
+    validate::<f32>("1e-1000").unwrap();
+    validate::<f32>("-1e-1000").unwrap();
+}
+
+#[test]
+fn test_validate_real() {
+    // Most of the arbitrary values come from checking against <http://weitz.de/ieee/>.
+    let r = &BigRational::from_float(10.0).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 10, 0).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 10, -1).unwrap_err();
+    FloatRes::<f32>::validate_real(r.clone(), 10, 1).unwrap_err();
+
+    let r = &BigRational::from_float(0.25).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 1, -2).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 2, -2).unwrap_err();
+
+    let r = &BigRational::from_float(1234.5678).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101011, -13).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101010, -13).unwrap_err();
+    FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101100, -13).unwrap_err();
+
+    let r = &BigRational::from_float(-1234.5678).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101011, -13).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101010, -13).unwrap_err();
+    FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101100, -13).unwrap_err();
+}
+
+#[test]
+#[allow(unused)]
+fn test_validate_real_rounding() {
+    // Check that we catch when values don't round to even.
+
+    // For f32, the cutoff between 1.0 and the next value up (1.0000001) is
+    // 1.000000059604644775390625. Anything below it should round down, anything above it should
+    // round up, and the value itself should round _down_ because `1.0` has an even significand but
+    // 1.0000001 is odd.
+    let v1_low_down = Rational::parse("1.00000005960464477539062499999").expect_finite();
+    let v1_mid_down = Rational::parse("1.000000059604644775390625").expect_finite();
+    let v1_high_up = Rational::parse("1.00000005960464477539062500001").expect_finite();
+
+    let exp = -(f32::MAN_BITS as i32);
+    let v1_down_sig = 1 << f32::MAN_BITS;
+    let v1_up_sig = (1 << f32::MAN_BITS) | 0b1;
+
+    FloatRes::<f32>::validate_real(v1_low_down.clone(), v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v1_mid_down.clone(), v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v1_high_up.clone(), v1_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v1_low_down.clone(), -v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v1_mid_down.clone(), -v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v1_high_up.clone(), -v1_up_sig, exp).unwrap();
+
+    // 1.000000178813934326171875 is between 1.0000001 and the next value up, 1.0000002. The middle
+    // value here should round _up_ since 1.0000002 has an even mantissa.
+    let v2_low_down = Rational::parse("1.00000017881393432617187499999").expect_finite();
+    let v2_mid_up = Rational::parse("1.000000178813934326171875").expect_finite();
+    let v2_high_up = Rational::parse("1.00000017881393432617187500001").expect_finite();
+
+    let v2_down_sig = v1_up_sig;
+    let v2_up_sig = (1 << f32::MAN_BITS) | 0b10;
+
+    FloatRes::<f32>::validate_real(v2_low_down.clone(), v2_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v2_mid_up.clone(), v2_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v2_high_up.clone(), v2_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v2_low_down.clone(), -v2_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v2_mid_up.clone(), -v2_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v2_high_up.clone(), -v2_up_sig, exp).unwrap();
+
+    // Rounding the wrong direction should error
+    for res in [
+        FloatRes::<f32>::validate_real(v1_mid_down.clone(), v1_up_sig, exp),
+        FloatRes::<f32>::validate_real(v2_mid_up.clone(), v2_down_sig, exp),
+        FloatRes::<f32>::validate_real(-v1_mid_down.clone(), -v1_up_sig, exp),
+        FloatRes::<f32>::validate_real(-v2_mid_up.clone(), -v2_down_sig, exp),
+    ] {
+        let e = res.unwrap_err();
+        let CheckFailure::InvalidReal { incorrect_midpoint_rounding: true, .. } = e else {
+            panic!("{e:?}");
+        };
+    }
+}
+
+/// Just a quick check that the constants are what we expect.
+#[test]
+fn check_constants() {
+    assert_eq!(f32::constants().max.to_f32().unwrap(), f32::MAX);
+    assert_eq!(f32::constants().min_subnormal.to_f32().unwrap(), f32::from_bits(0x1));
+    assert_eq!(f64::constants().max.to_f64().unwrap(), f64::MAX);
+    assert_eq!(f64::constants().min_subnormal.to_f64().unwrap(), f64::from_bits(0x1));
+}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 00973865915..9256330ac7c 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -2062,16 +2062,23 @@ pub(super) fn item_path(ty: ItemType, name: &str) -> String {
 
 fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> String {
     let mut bounds = String::new();
-    if !t_bounds.is_empty() {
-        if !trait_alias {
+    if t_bounds.is_empty() {
+        return bounds;
+    }
+    let has_lots_of_bounds = t_bounds.len() > 2;
+    let inter_str = if has_lots_of_bounds { "\n    + " } else { " + " };
+    if !trait_alias {
+        if has_lots_of_bounds {
+            bounds.push_str(":\n    ");
+        } else {
             bounds.push_str(": ");
         }
-        for (i, p) in t_bounds.iter().enumerate() {
-            if i > 0 {
-                bounds.push_str(" + ");
-            }
-            bounds.push_str(&p.print(cx).to_string());
+    }
+    for (i, p) in t_bounds.iter().enumerate() {
+        if i > 0 {
+            bounds.push_str(inter_str);
         }
+        bounds.push_str(&p.print(cx).to_string());
     }
     bounds
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 28ed94432c8..41c506f33dc 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -831,6 +831,10 @@ pre, .rustdoc.src .example-wrap {
 	background: var(--table-alt-row-background-color);
 }
 
+.docblock .stab, .docblock-short .stab {
+	display: inline-block;
+}
+
 /* "where ..." clauses with block display are also smaller */
 div.where {
 	white-space: pre-wrap;
@@ -953,6 +957,7 @@ table,
 	display: table;
 	padding: 0;
 	margin: 0;
+	width: 100%;
 }
 .item-table > li {
 	display: table-row;
@@ -2178,7 +2183,6 @@ in src-script.js and main.js
 		width: 33%;
 	}
 	.item-table > li > div {
-		padding-bottom: 5px;
 		word-break: break-all;
 	}
 }
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index a2e7907b532..e0bea5f053d 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -157,6 +157,7 @@ static TARGETS: &[&str] = &[
     "wasm32-wasi",
     "wasm32-wasip1",
     "wasm32-wasip1-threads",
+    "wasm32-wasip2",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",
     "x86_64-fortanix-unknown-sgx",
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index b4522de6897..8be38dc855f 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -7,7 +7,7 @@ pub struct GitConfig<'a> {
 }
 
 /// Runs a command and returns the output
-fn output_result(cmd: &mut Command) -> Result<String, String> {
+pub fn output_result(cmd: &mut Command) -> Result<String, String> {
     let output = match cmd.stderr(Stdio::inherit()).output() {
         Ok(status) => status,
         Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)),
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject a2b58c3dad4d554ba01ed6c45c41ff85390560f
+Subproject 5f6b9a92201d78af75dc24f14662c3e2dacbbbe
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index cce8617821e..b179d7b5249 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -16,6 +16,7 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_must_use_ty;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{return_ty, trait_ref_of_method};
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 
 use core::ops::ControlFlow;
 
@@ -117,11 +118,11 @@ fn check_needless_must_use(
         // Ignore async functions unless Future::Output type is a must_use type
         if sig.header.is_async() {
             let infcx = cx.tcx.infer_ctxt().build();
-            if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id))
+            if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id))
                 && !is_must_use_ty(cx, future_ty)
             {
                 return;
-            }
+            };
         }
 
         span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 1fd8faf3ea8..e6506709774 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
-use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 95ae591884b..0d3786dad4b 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -56,19 +56,18 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
         let Ok(impls) = cx.tcx.crate_inherent_impls(()) else {
             return;
         };
-        let inherent_impls = cx
-            .tcx
-            .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true));
 
-        for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| {
-            impls.len() > 1
+        for (&id, impl_ids) in &impls.inherent_impls {
+            if impl_ids.len() < 2
             // Check for `#[allow]` on the type definition
-            && !is_lint_allowed(
+            || is_lint_allowed(
                 cx,
                 MULTIPLE_INHERENT_IMPL,
                 cx.tcx.local_def_id_to_hir_id(id),
-            )
-        }) {
+            ) {
+                continue;
+            }
+
             for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
                 let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity();
                 match type_map.entry(impl_ty) {
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 0ecfa7baa72..9d326c06eff 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -15,6 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use std::ops::Deref;
 
 declare_clippy_lint! {
@@ -159,7 +160,7 @@ impl NoEffect {
                                 // Remove `impl Future<Output = T>` to get `T`
                                 if cx.tcx.ty_is_opaque_future(ret_ty)
                                     && let Some(true_ret_ty) =
-                                        cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty)
+                                        cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty)
                                 {
                                     ret_ty = true_ret_ty;
                                 }
diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr
index 3c7577dd003..83451fb658d 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics.stderr
+++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL | const S: A = B;
    |              ^ expected `A`, found `B`
--Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC
+-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs
index cbe94af3510..ca2a6f4b8c8 100644
--- a/src/tools/collect-license-metadata/src/main.rs
+++ b/src/tools/collect-license-metadata/src/main.rs
@@ -6,16 +6,6 @@ use crate::licenses::LicensesInterner;
 use anyhow::Error;
 use std::path::PathBuf;
 
-// Some directories have too many slight license differences that'd result in a
-// huge report, and could be considered a standalone project anyway. Those
-// directories are "condensed" into a single licensing block for ease of
-// reading, merging the licensing information.
-//
-// For every `(dir, file)``, every file in `dir` is considered to have the
-// license info of `file`.
-const CONDENSED_DIRECTORIES: &[(&str, &str)] =
-    &[("./src/llvm-project/", "./src/llvm-project/README.md")];
-
 fn main() -> Result<(), Error> {
     let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into();
     let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into();
diff --git a/src/tools/collect-license-metadata/src/path_tree.rs b/src/tools/collect-license-metadata/src/path_tree.rs
index fc8756d9a2e..b27fb7f9225 100644
--- a/src/tools/collect-license-metadata/src/path_tree.rs
+++ b/src/tools/collect-license-metadata/src/path_tree.rs
@@ -4,7 +4,7 @@
 //! passes over the tree to remove redundant information.
 
 use crate::licenses::{License, LicenseId, LicensesInterner};
-use std::collections::{BTreeMap, BTreeSet};
+use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 
 #[derive(serde::Serialize)]
@@ -12,7 +12,6 @@ use std::path::{Path, PathBuf};
 pub(crate) enum Node<L> {
     Root { children: Vec<Node<L>> },
     Directory { name: PathBuf, children: Vec<Node<L>>, license: Option<L> },
-    CondensedDirectory { name: PathBuf, licenses: Vec<L> },
     File { name: PathBuf, license: L },
     Group { files: Vec<PathBuf>, directories: Vec<PathBuf>, license: L },
     Empty,
@@ -59,8 +58,6 @@ impl Node<LicenseId> {
                             directories.entry(name).or_insert_with(Vec::new).append(&mut children);
                         }
                         file @ Node::File { .. } => files.push(file),
-                        // Propagate condensed directories as-is.
-                        condensed @ Node::CondensedDirectory { .. } => files.push(condensed),
                         Node::Empty => {}
                         Node::Root { .. } => {
                             panic!("can't have a root inside another element");
@@ -87,7 +84,6 @@ impl Node<LicenseId> {
             }
             Node::Empty => {}
             Node::File { .. } => {}
-            Node::CondensedDirectory { .. } => {}
             Node::Group { .. } => {
                 panic!("Group should not be present at this stage");
             }
@@ -134,7 +130,6 @@ impl Node<LicenseId> {
                 }
             }
             Node::File { .. } => {}
-            Node::CondensedDirectory { .. } => {}
             Node::Group { .. } => panic!("group should not be present at this stage"),
             Node::Empty => {}
         }
@@ -177,9 +172,6 @@ impl Node<LicenseId> {
                             Node::Directory { name: child_child_name, .. } => {
                                 *child_child_name = child_name.join(&child_child_name);
                             }
-                            Node::CondensedDirectory { name: child_child_name, .. } => {
-                                *child_child_name = child_name.join(&child_child_name);
-                            }
                             Node::File { name: child_child_name, .. } => {
                                 *child_child_name = child_name.join(&child_child_name);
                             }
@@ -194,7 +186,6 @@ impl Node<LicenseId> {
             }
             Node::Empty => {}
             Node::File { .. } => {}
-            Node::CondensedDirectory { .. } => {}
             Node::Group { .. } => panic!("Group should not be present at this stage"),
         }
     }
@@ -262,7 +253,6 @@ impl Node<LicenseId> {
                 }
             }
             Node::File { .. } => {}
-            Node::CondensedDirectory { .. } => {}
             Node::Group { .. } => panic!("FileGroup should not be present at this stage"),
             Node::Empty => {}
         }
@@ -278,7 +268,6 @@ impl Node<LicenseId> {
                 }
                 children.retain(|child| !matches!(child, Node::Empty));
             }
-            Node::CondensedDirectory { .. } => {}
             Node::Group { .. } => {}
             Node::File { .. } => {}
             Node::Empty => {}
@@ -302,24 +291,7 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
     // Ensure reproducibility of all future steps.
     input.sort();
 
-    let mut condensed_directories = BTreeMap::new();
-    'outer: for (path, license) in input {
-        // Files in condensed directories are handled separately.
-        for (condensed_directory, allowed_file) in super::CONDENSED_DIRECTORIES {
-            if path.starts_with(condensed_directory) {
-                if path.as_path() == Path::new(allowed_file) {
-                    // The licence on our allowed file is used to represent the entire directory
-                    condensed_directories
-                        .entry(*condensed_directory)
-                        .or_insert_with(BTreeSet::new)
-                        .insert(license);
-                } else {
-                    // don't add the file
-                }
-                continue 'outer;
-            }
-        }
-
+    for (path, license) in input {
         let mut node = Node::File { name: path.file_name().unwrap().into(), license };
         for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() {
             node = Node::Directory {
@@ -332,22 +304,6 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
         children.push(node);
     }
 
-    for (path, licenses) in condensed_directories {
-        let path = Path::new(path);
-        let mut node = Node::CondensedDirectory {
-            name: path.file_name().unwrap().into(),
-            licenses: licenses.iter().copied().collect(),
-        };
-        for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() {
-            node = Node::Directory {
-                name: component.as_os_str().into(),
-                children: vec![node],
-                license: None,
-            };
-        }
-        children.push(node);
-    }
-
     Node::Root { children }
 }
 
@@ -376,10 +332,6 @@ pub(crate) fn expand_interned_licenses(
         Node::Group { files, directories, license } => {
             Node::Group { files, directories, license: interner.resolve(license) }
         }
-        Node::CondensedDirectory { name, licenses } => Node::CondensedDirectory {
-            name,
-            licenses: licenses.into_iter().map(|license| interner.resolve(license)).collect(),
-        },
         Node::Empty => Node::Empty,
     }
 }
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index da7f03441e7..bc66dcbfb94 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -760,8 +760,14 @@ pub fn output_testname_unique(
 /// test/revision should reside. Example:
 ///   /path/to/build/host-triple/test/ui/relative/testname.revision.mode/
 pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
-    output_relative_path(config, &testpaths.relative_dir)
-        .join(output_testname_unique(config, testpaths, revision))
+    // In run-make tests, constructing a relative path + unique testname causes a double layering
+    // since revisions are not supported, causing unnecessary nesting.
+    if config.mode == Mode::RunMake {
+        output_relative_path(config, &testpaths.relative_dir)
+    } else {
+        output_relative_path(config, &testpaths.relative_dir)
+            .join(output_testname_unique(config, testpaths, revision))
+    }
 }
 
 /// Absolute path to the base filename used as output for the given
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 01228869617..53988203136 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3433,29 +3433,51 @@ impl<'test> TestCx<'test> {
 
     fn run_rmake_v2_test(&self) {
         // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe
-        // (`rmake.rs`) to run the actual tests. The support library is already built as a tool
-        // dylib and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`.
+        // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust
+        // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`.
         //
-        // 1. We need to build the recipe `rmake.rs` and link in the support library.
-        // 2. We need to run the recipe to build and run the tests.
-        let cwd = env::current_dir().unwrap();
-        let src_root = self.config.src_base.parent().unwrap().parent().unwrap();
-        let src_root = cwd.join(&src_root);
-        let build_root = self.config.build_base.parent().unwrap().parent().unwrap();
-        let build_root = cwd.join(&build_root);
+        // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support`
+        //    library.
+        // 2. We need to run the recipe binary.
+
+        // So we assume the rust-lang/rust project setup looks like the following (our `.` is the
+        // top-level directory, irrelevant entries to our purposes omitted):
+        //
+        // ```
+        // .                               // <- `source_root`
+        // ├── build/                      // <- `build_root`
+        // ├── compiler/
+        // ├── library/
+        // ├── src/
+        // │  └── tools/
+        // │     └── run_make_support/
+        // └── tests
+        //    └── run-make/
+        // ```
+
+        // `source_root` is the top-level directory containing the rust-lang/rust checkout.
+        let source_root =
+            self.config.find_rust_src_root().expect("could not determine rust source root");
+        // `self.config.build_base` is actually the build base folder + "test" + test suite name, it
+        // looks like `build/<host_triple>/test/run-make`. But we want `build/<host_triple>/`. Note
+        // that the `build` directory does not need to be called `build`, nor does it need to be
+        // under `source_root`, so we must compute it based off of `self.config.build_base`.
+        let build_root =
+            self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf();
 
         // We construct the following directory tree for each rmake.rs test:
         // ```
-        // base_dir/
+        // <base_dir>/
         //     rmake.exe
         //     rmake_out/
         // ```
-        // having the executable separate from the output artifacts directory allows the recipes to
-        // `remove_dir_all($TMPDIR)` without running into permission denied issues because
-        // the executable is not under the `rmake_out/` directory.
+        // having the recipe executable separate from the output artifacts directory allows the
+        // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove
+        // a currently running executable because the recipe executable is not under the
+        // `rmake_out/` directory.
         //
         // This setup intentionally diverges from legacy Makefile run-make tests.
-        let base_dir = cwd.join(self.output_base_name());
+        let base_dir = self.output_base_name();
         if base_dir.exists() {
             self.aggressive_rm_rf(&base_dir).unwrap();
         }
@@ -3477,120 +3499,186 @@ impl<'test> TestCx<'test> {
             }
         }
 
-        // HACK: assume stageN-target, we only want stageN.
+        // `self.config.stage_id` looks like `stage1-<target_triple>`, but we only want
+        // the `stage1` part as that is what the output directories of bootstrap are prefixed with.
+        // Note that this *assumes* build layout from bootstrap is produced as:
+        //
+        // ```
+        // build/<target_triple>/          // <- this is `build_root`
+        // ├── stage0
+        // ├── stage0-bootstrap-tools
+        // ├── stage0-codegen
+        // ├── stage0-rustc
+        // ├── stage0-std
+        // ├── stage0-sysroot
+        // ├── stage0-tools
+        // ├── stage0-tools-bin
+        // ├── stage1
+        // ├── stage1-std
+        // ├── stage1-tools
+        // ├── stage1-tools-bin
+        // └── test
+        // ```
+        // FIXME(jieyouxu): improve the communication between bootstrap and compiletest here so
+        // we don't have to hack out a `stageN`.
         let stage = self.config.stage_id.split('-').next().unwrap();
 
-        // First, we construct the path to the built support library.
-        let mut support_lib_path = PathBuf::new();
-        support_lib_path.push(&build_root);
-        support_lib_path.push(format!("{}-tools-bin", stage));
-        support_lib_path.push("librun_make_support.rlib");
+        // In order to link in the support library as a rlib when compiling recipes, we need three
+        // paths:
+        // 1. Path of the built support library rlib itself.
+        // 2. Path of the built support library's dependencies directory.
+        // 3. Path of the built support library's dependencies' dependencies directory.
+        //
+        // The paths look like
+        //
+        // ```
+        // build/<target_triple>/
+        // ├── stageN-tools-bin/
+        // │   └── librun_make_support.rlib       // <- support rlib itself
+        // ├── stageN-tools/
+        // │   ├── release/deps/                  // <- deps of deps
+        // │   └── <host_triple>/release/deps/    // <- deps
+        // ```
+        //
+        // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the
+        // support lib and its deps are organized, can't we copy them to the tools-bin dir as
+        // well?), but this seems to work for now.
 
-        let mut stage_std_path = PathBuf::new();
-        stage_std_path.push(&build_root);
-        stage_std_path.push(&stage);
-        stage_std_path.push("lib");
+        let stage_tools_bin = build_root.join(format!("{stage}-tools-bin"));
+        let support_lib_path = stage_tools_bin.join("librun_make_support.rlib");
 
-        // Then, we need to build the recipe `rmake.rs` and link in the support library.
-        let recipe_bin = base_dir.join(if self.config.target.contains("windows") {
-            "rmake.exe"
-        } else {
-            "rmake"
-        });
-
-        let mut support_lib_deps = PathBuf::new();
-        support_lib_deps.push(&build_root);
-        support_lib_deps.push(format!("{}-tools", stage));
-        support_lib_deps.push(&self.config.host);
-        support_lib_deps.push("release");
-        support_lib_deps.push("deps");
-
-        let mut support_lib_deps_deps = PathBuf::new();
-        support_lib_deps_deps.push(&build_root);
-        support_lib_deps_deps.push(format!("{}-tools", stage));
-        support_lib_deps_deps.push("release");
-        support_lib_deps_deps.push("deps");
-
-        debug!(?support_lib_deps);
-        debug!(?support_lib_deps_deps);
-
-        let orig_dylib_env_paths =
+        let stage_tools = build_root.join(format!("{stage}-tools"));
+        let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps");
+        let support_lib_deps_deps = stage_tools.join("release").join("deps");
+
+        // To compile the recipe with rustc, we need to provide suitable dynamic library search
+        // paths to rustc. This includes both:
+        // 1. The "base" dylib search paths that was provided to compiletest, e.g. `LD_LIBRARY_PATH`
+        //    on some linux distros.
+        // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc.
+
+        let base_dylib_search_paths =
             Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap()));
 
-        let mut host_dylib_env_paths = Vec::new();
-        host_dylib_env_paths.push(cwd.join(&self.config.compile_lib_path));
-        host_dylib_env_paths.extend(orig_dylib_env_paths.iter().cloned());
-        let host_dylib_env_paths = env::join_paths(host_dylib_env_paths).unwrap();
+        let host_dylib_search_paths = {
+            let mut paths = vec![self.config.compile_lib_path.clone()];
+            paths.extend(base_dylib_search_paths.iter().cloned());
+            paths
+        };
+
+        // Calculate the paths of the recipe binary. As previously discussed, this is placed at
+        // `<base_dir>/<bin_name>` with `bin_name` being `rmake` or `rmake.exe` depending on
+        // platform.
+        let recipe_bin = {
+            let mut p = base_dir.join("rmake");
+            p.set_extension(env::consts::EXE_EXTENSION);
+            p
+        };
 
-        let mut cmd = Command::new(&self.config.rustc_path);
-        cmd.arg("-o")
+        let mut rustc = Command::new(&self.config.rustc_path);
+        rustc
+            .arg("-o")
             .arg(&recipe_bin)
+            // Specify library search paths for `run_make_support`.
             .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy()))
             .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy()))
             .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy()))
+            // Provide `run_make_support` as extern prelude, so test writers don't need to write
+            // `extern run_make_support;`.
             .arg("--extern")
             .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
             .arg("--edition=2021")
             .arg(&self.testpaths.file.join("rmake.rs"))
-            .env("TARGET", &self.config.target)
-            .env("PYTHON", &self.config.python)
-            .env("RUST_BUILD_STAGE", &self.config.stage_id)
-            .env("RUSTC", cwd.join(&self.config.rustc_path))
-            .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
-            .env(dylib_env_var(), &host_dylib_env_paths)
-            .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
-            .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
-            .env("LLVM_COMPONENTS", &self.config.llvm_components);
+            // Provide necessary library search paths for rustc.
+            .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap());
 
         // In test code we want to be very pedantic about values being silently discarded that are
         // annotated with `#[must_use]`.
-        cmd.arg("-Dunused_must_use");
-
+        rustc.arg("-Dunused_must_use");
+
+        // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc
+        // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is
+        // > compiled using the bootstrap rustc wrapper which sets `--sysroot
+        // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile
+        // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the
+        // > `libstd.rlib` against which `librun_make_support.rlib` is compiled.
+        //
+        // The gist here is that we have to pass the proper stage0 sysroot if we want
+        //
+        // ```
+        // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0
+        // ```
+        //
+        // to work correctly.
+        //
+        // See <https://github.com/rust-lang/rust/pull/122248> for more background.
         if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() {
-            let mut stage0_sysroot = build_root.clone();
-            stage0_sysroot.push("stage0-sysroot");
-            debug!(?stage0_sysroot);
-            debug!(exists = stage0_sysroot.exists());
-
-            cmd.arg("--sysroot").arg(&stage0_sysroot);
+            let stage0_sysroot = build_root.join("stage0-sysroot");
+            rustc.arg("--sysroot").arg(&stage0_sysroot);
         }
 
-        let res = self.run_command_to_procres(&mut cmd);
+        // Now run rustc to build the recipe.
+        let res = self.run_command_to_procres(&mut rustc);
         if !res.status.success() {
             self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res);
         }
 
-        // Finally, we need to run the recipe binary to build and run the actual tests.
-        debug!(?recipe_bin);
+        // To actually run the recipe, we have to provide the recipe with a bunch of information
+        // provided through env vars.
+
+        // Compute stage-specific standard library paths.
+        let stage_std_path = build_root.join(&stage).join("lib");
 
-        let mut dylib_env_paths = orig_dylib_env_paths.clone();
-        dylib_env_paths.push(support_lib_path.parent().unwrap().to_path_buf());
-        dylib_env_paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib"));
-        let dylib_env_paths = env::join_paths(dylib_env_paths).unwrap();
+        // Compute dynamic library search paths for recipes.
+        let recipe_dylib_search_paths = {
+            let mut paths = base_dylib_search_paths.clone();
+            paths.push(support_lib_path.parent().unwrap().to_path_buf());
+            paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib"));
+            paths
+        };
 
-        let mut target_rpath_env_path = Vec::new();
-        target_rpath_env_path.push(&rmake_out_dir);
-        target_rpath_env_path.extend(&orig_dylib_env_paths);
-        let target_rpath_env_path = env::join_paths(target_rpath_env_path).unwrap();
+        // Compute runtime library search paths for recipes. This is target-specific.
+        let target_runtime_dylib_search_paths = {
+            let mut paths = vec![rmake_out_dir.clone()];
+            paths.extend(base_dylib_search_paths.iter().cloned());
+            paths
+        };
 
+        // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and
+        // `TARGET_RPATH_DIR`, it is **extremely** confusing!
         let mut cmd = Command::new(&recipe_bin);
         cmd.current_dir(&rmake_out_dir)
             .stdout(Stdio::piped())
             .stderr(Stdio::piped())
+            // Provide the target-specific env var that is used to record dylib search paths. For
+            // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows.
             .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
-            .env("TARGET_RPATH_ENV", &target_rpath_env_path)
-            .env(dylib_env_var(), &dylib_env_paths)
+            // Provide the dylib search paths.
+            .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap())
+            // Provide runtime dylib search paths.
+            .env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap())
+            // Provide the target.
             .env("TARGET", &self.config.target)
+            // Some tests unfortunately still need Python, so provide path to a Python interpreter.
             .env("PYTHON", &self.config.python)
-            .env("SOURCE_ROOT", &src_root)
-            .env("RUST_BUILD_STAGE", &self.config.stage_id)
-            .env("RUSTC", cwd.join(&self.config.rustc_path))
-            .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
-            .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
+            // Provide path to checkout root. This is the top-level directory containing
+            // rust-lang/rust checkout.
+            .env("SOURCE_ROOT", &source_root)
+            // Provide path to stage-corresponding rustc.
+            .env("RUSTC", &self.config.rustc_path)
+            // Provide the directory to libraries that are needed to run the *compiler*. This is not
+            // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the
+            // recipe wants to invoke rustc.
+            .env("HOST_RPATH_DIR", &self.config.compile_lib_path)
+            // Provide the directory to libraries that might be needed to run compiled binaries
+            // (further compiled by the recipe!).
+            .env("TARGET_RPATH_DIR", &self.config.run_lib_path)
+            // Provide which LLVM components are available (e.g. which LLVM components are provided
+            // through a specific CI runner).
             .env("LLVM_COMPONENTS", &self.config.llvm_components);
 
         if let Some(ref rustdoc) = self.config.rustdoc_path {
-            cmd.env("RUSTDOC", cwd.join(rustdoc));
+            cmd.env("RUSTDOC", source_root.join(rustdoc));
         }
 
         if let Some(ref node) = self.config.nodejs {
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 558e87290b0..d91b258162e 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -1,5 +1,4 @@
 use anyhow::Error;
-use std::collections::BTreeSet;
 use std::io::Write;
 use std::path::PathBuf;
 
@@ -27,7 +26,7 @@ fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(
             }
         }
         Node::Directory { name, children, license } => {
-            render_license(&prefix, std::iter::once(name), license.iter(), buffer)?;
+            render_license(&prefix, std::iter::once(name), license.as_ref(), buffer)?;
             if !children.is_empty() {
                 writeln!(buffer, "{prefix}")?;
                 writeln!(buffer, "{prefix}*Exceptions:*")?;
@@ -37,19 +36,11 @@ fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(
                 }
             }
         }
-        Node::CondensedDirectory { name, licenses } => {
-            render_license(&prefix, std::iter::once(name), licenses.iter(), buffer)?;
-        }
         Node::Group { files, directories, license } => {
-            render_license(
-                &prefix,
-                directories.iter().chain(files.iter()),
-                std::iter::once(license),
-                buffer,
-            )?;
+            render_license(&prefix, directories.iter().chain(files.iter()), Some(license), buffer)?;
         }
         Node::File { name, license } => {
-            render_license(&prefix, std::iter::once(name), std::iter::once(license), buffer)?;
+            render_license(&prefix, std::iter::once(name), Some(license), buffer)?;
         }
     }
 
@@ -59,27 +50,17 @@ fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(
 fn render_license<'a>(
     prefix: &str,
     names: impl Iterator<Item = &'a String>,
-    licenses: impl Iterator<Item = &'a License>,
+    license: Option<&License>,
     buffer: &mut Vec<u8>,
 ) -> Result<(), Error> {
-    let mut spdxs = BTreeSet::new();
-    let mut copyrights = BTreeSet::new();
-    for license in licenses {
-        spdxs.insert(&license.spdx);
-        for copyright in &license.copyright {
-            copyrights.insert(copyright);
-        }
-    }
-
     for name in names {
         writeln!(buffer, "{prefix}**`{name}`**  ")?;
     }
-    for spdx in spdxs.iter() {
-        writeln!(buffer, "{prefix}License: `{spdx}`  ")?;
-    }
-    for (i, copyright) in copyrights.iter().enumerate() {
-        let suffix = if i == copyrights.len() - 1 { "" } else { "  " };
-        writeln!(buffer, "{prefix}Copyright: {copyright}{suffix}")?;
+    if let Some(license) = license {
+        writeln!(buffer, "{prefix}License: `{}`", license.spdx)?;
+        for copyright in license.copyright.iter() {
+            writeln!(buffer, "{prefix}Copyright: {copyright}")?;
+        }
     }
 
     Ok(())
@@ -95,7 +76,6 @@ struct Metadata {
 pub(crate) enum Node {
     Root { children: Vec<Node> },
     Directory { name: String, children: Vec<Node>, license: Option<License> },
-    CondensedDirectory { name: String, licenses: Vec<License> },
     File { name: String, license: License },
     Group { files: Vec<String>, directories: Vec<String>, license: License },
 }
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
index 9eaa234bfaf..0d827ab2e72 100644
--- a/src/tools/lint-docs/src/groups.rs
+++ b/src/tools/lint-docs/src/groups.rs
@@ -24,6 +24,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
         "keyword-idents",
         "Lints that detect identifiers which will be come keywords in later editions",
     ),
+    ("deprecated-safe", "Lints for functions which were erroneously marked as safe in the past"),
 ];
 
 type LintGroups = BTreeMap<String, BTreeSet<String>>;
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index 5e8ad7ed312..b116bd08e3a 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -229,6 +229,8 @@ impl LlvmAr {
         Self { cmd }
     }
 
+    /// Automatically pass the commonly used arguments `rcus`, used for combining one or more
+    /// input object files into one output static library file.
     pub fn obj_to_ar(&mut self) -> &mut Self {
         self.cmd.arg("rcus");
         self
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index e6a45f57de6..b85191970de 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -3,6 +3,10 @@
 //! 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.
 
+// We want to control use declaration ordering and spacing (and preserve use group comments), so
+// skip rustfmt on this file.
+#![cfg_attr(rustfmt, rustfmt::skip)]
+
 mod command;
 mod macros;
 mod util;
@@ -18,6 +22,8 @@ pub mod scoped_run;
 pub mod string;
 pub mod targets;
 
+// Internally we call our fs-related support module as `fs`, but re-export its content as `rfs`
+// to tests to avoid colliding with commonly used `use std::fs;`.
 mod fs;
 
 /// [`std::fs`] wrappers and assorted filesystem-related helpers. Public to tests as `rfs` to not be
diff --git a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
index cf3d85b4da3..4ec74c0742a 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
@@ -21,6 +21,7 @@ impl PanicContext {
     #[allow(clippy::print_stderr)]
     fn init() {
         let default_hook = panic::take_hook();
+        #[allow(deprecated)]
         let hook = move |panic_info: &panic::PanicInfo<'_>| {
             with_ctx(|ctx| {
                 if !ctx.is_empty() {
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
new file mode 100644
index 00000000000..75b89a162e9
--- /dev/null
+++ b/src/tools/rustbook/Cargo.lock
@@ -0,0 +1,1762 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ammonia"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459"
+dependencies = [
+ "html5ever",
+ "maplit",
+ "once_cell",
+ "tendril",
+ "url",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bstr"
+version = "1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
+dependencies = [
+ "memchr",
+ "regex-automata",
+ "serde",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "cc"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+ "terminal_size",
+]
+
+[[package]]
+name = "clap_complete"
+version = "4.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b4be9c4c4b1f30b78d8a750e0822b6a6102d97e62061c583a6c1dea2dfb33ae"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "dbus"
+version = "0.9.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b"
+dependencies = [
+ "libc",
+ "libdbus-sys",
+ "winapi",
+]
+
+[[package]]
+name = "deranged"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
+[[package]]
+name = "elasticlunr-rs"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41e83863a500656dfa214fee6682de9c5b9f03de6860fec531235ed2ae9f6571"
+dependencies = [
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "env_filter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "humantime",
+ "log",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+
+[[package]]
+name = "flate2"
+version = "1.0.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
+dependencies = [
+ "mac",
+ "new_debug_unreachable",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getopts"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "handlebars"
+version = "5.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b"
+dependencies = [
+ "log",
+ "pest",
+ "pest_derive",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "html5ever"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
+dependencies = [
+ "log",
+ "mac",
+ "markup5ever",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "js-sys"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.155"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+
+[[package]]
+name = "libdbus-sys"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
+name = "linereader"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d921fea6860357575519aca014c6e22470585accdd543b370c404a8a72d0dd1d"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "mac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
+
+[[package]]
+name = "maplit"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
+
+[[package]]
+name = "markup5ever"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
+dependencies = [
+ "log",
+ "phf",
+ "phf_codegen",
+ "string_cache",
+ "string_cache_codegen",
+ "tendril",
+]
+
+[[package]]
+name = "mdbook"
+version = "0.4.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5"
+dependencies = [
+ "ammonia",
+ "anyhow",
+ "chrono",
+ "clap",
+ "clap_complete",
+ "elasticlunr-rs",
+ "env_logger",
+ "handlebars",
+ "log",
+ "memchr",
+ "once_cell",
+ "opener",
+ "pulldown-cmark",
+ "regex",
+ "serde",
+ "serde_json",
+ "shlex",
+ "tempfile",
+ "toml 0.5.11",
+ "topological-sort",
+]
+
+[[package]]
+name = "mdbook-i18n-helpers"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c8f972ab672d366c3dad77ea5aa7bae68db2d25fbeb889849f97469d7b658e4"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "mdbook",
+ "polib",
+ "pulldown-cmark",
+ "pulldown-cmark-to-cmark",
+ "regex",
+ "semver",
+ "serde_json",
+ "syntect",
+ "textwrap",
+]
+
+[[package]]
+name = "mdbook-trpl-listing"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "mdbook",
+ "pulldown-cmark",
+ "pulldown-cmark-to-cmark",
+ "serde_json",
+ "thiserror",
+ "toml 0.8.14",
+ "xmlparser",
+]
+
+[[package]]
+name = "mdbook-trpl-note"
+version = "1.0.0"
+dependencies = [
+ "clap",
+ "mdbook",
+ "pulldown-cmark",
+ "pulldown-cmark-to-cmark",
+ "serde_json",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
+[[package]]
+name = "normpath"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "onig"
+version = "6.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+ "once_cell",
+ "onig_sys",
+]
+
+[[package]]
+name = "onig_sys"
+version = "69.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
+name = "opener"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0"
+dependencies = [
+ "bstr",
+ "dbus",
+ "normpath",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pest"
+version = "2.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95"
+dependencies = [
+ "memchr",
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
+
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_shared 0.11.2",
+]
+
+[[package]]
+name = "phf_codegen"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
+dependencies = [
+ "phf_generator 0.11.2",
+ "phf_shared 0.11.2",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
+dependencies = [
+ "phf_shared 0.10.0",
+ "rand",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+dependencies = [
+ "phf_shared 0.11.2",
+ "rand",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+
+[[package]]
+name = "plist"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
+dependencies = [
+ "base64",
+ "indexmap",
+ "quick-xml",
+ "serde",
+ "time",
+]
+
+[[package]]
+name = "polib"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b393b155cf9be86249cba1b56cc81be0e6212c66d94ac0d76d37a1761f3bb1b"
+dependencies = [
+ "linereader",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "precomputed-hash"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "pulldown-cmark"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
+dependencies = [
+ "bitflags 2.6.0",
+ "getopts",
+ "memchr",
+ "pulldown-cmark-escape",
+ "unicase",
+]
+
+[[package]]
+name = "pulldown-cmark-escape"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
+
+[[package]]
+name = "pulldown-cmark-to-cmark"
+version = "13.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f609795c8d835f79dcfcf768415b9fb57ef1b74891e99f86e73f43a7a257163b"
+dependencies = [
+ "pulldown-cmark",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+
+[[package]]
+name = "rustbook"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "env_logger",
+ "mdbook",
+ "mdbook-i18n-helpers",
+ "mdbook-trpl-listing",
+ "mdbook-trpl-note",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+dependencies = [
+ "bitflags 2.6.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
+[[package]]
+name = "serde"
+version = "1.0.204"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.204"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "string_cache"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
+dependencies = [
+ "new_debug_unreachable",
+ "once_cell",
+ "parking_lot",
+ "phf_shared 0.10.0",
+ "precomputed-hash",
+ "serde",
+]
+
+[[package]]
+name = "string_cache_codegen"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
+dependencies = [
+ "phf_generator 0.10.0",
+ "phf_shared 0.10.0",
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syntect"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
+dependencies = [
+ "bincode",
+ "bitflags 1.3.2",
+ "flate2",
+ "fnv",
+ "once_cell",
+ "onig",
+ "plist",
+ "regex-syntax",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "thiserror",
+ "walkdir",
+ "yaml-rust",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "rustix",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tendril"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
+dependencies = [
+ "futf",
+ "mac",
+ "utf-8",
+]
+
+[[package]]
+name = "terminal_size"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
+dependencies = [
+ "rustix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
+
+[[package]]
+name = "thiserror"
+version = "1.0.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "time"
+version = "0.3.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+
+[[package]]
+name = "time-macros"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "topological-sort"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+
+[[package]]
+name = "unicase"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
+
+[[package]]
+name = "url"
+version = "2.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf-8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.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_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[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_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "xmlparser"
+version = "0.13.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 95f1a5d6e1d..51ba58483c5 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -1,3 +1,5 @@
+[workspace]
+
 [package]
 name = "rustbook"
 version = "0.1.0"
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 4b50bcb38fd..158d5cc8ade 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,13 +1,9 @@
 run-make/branch-protection-check-IBT/Makefile
 run-make/c-dynamic-dylib/Makefile
 run-make/c-dynamic-rlib/Makefile
-run-make/c-static-dylib/Makefile
-run-make/c-static-rlib/Makefile
 run-make/c-unwind-abi-catch-lib-panic/Makefile
-run-make/c-unwind-abi-catch-panic/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
 run-make/cdylib-dylib-linkage/Makefile
-run-make/compiler-lookup-paths-2/Makefile
 run-make/compiler-rt-works-on-mingw/Makefile
 run-make/cross-lang-lto-clang/Makefile
 run-make/cross-lang-lto-pgo-smoketest/Makefile
@@ -21,9 +17,7 @@ run-make/emit-to-stdout/Makefile
 run-make/export-executable-symbols/Makefile
 run-make/extern-diff-internal-name/Makefile
 run-make/extern-flag-disambiguates/Makefile
-run-make/extern-fn-generic/Makefile
 run-make/extern-fn-reachable/Makefile
-run-make/extern-fn-with-union/Makefile
 run-make/extern-multiple-copies/Makefile
 run-make/extern-multiple-copies2/Makefile
 run-make/fmt-write-bloat/Makefile
@@ -33,18 +27,13 @@ run-make/foreign-rust-exceptions/Makefile
 run-make/incr-add-rust-src-component/Makefile
 run-make/incr-foreign-head-span/Makefile
 run-make/interdependent-c-libraries/Makefile
-run-make/issue-107094/Makefile
-run-make/issue-14698/Makefile
 run-make/issue-15460/Makefile
-run-make/issue-28595/Makefile
-run-make/issue-33329/Makefile
 run-make/issue-35164/Makefile
 run-make/issue-36710/Makefile
 run-make/issue-47551/Makefile
 run-make/issue-69368/Makefile
 run-make/issue-84395-lto-embed-bitcode/Makefile
 run-make/issue-88756-default-output/Makefile
-run-make/issue-97463-abi-param-passing/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/libtest-json/Makefile
@@ -52,11 +41,9 @@ run-make/libtest-junit/Makefile
 run-make/libtest-thread-limit/Makefile
 run-make/link-cfg/Makefile
 run-make/link-framework/Makefile
-run-make/linkage-attr-on-static/Makefile
 run-make/long-linker-command-lines-cmd-exe/Makefile
 run-make/long-linker-command-lines/Makefile
 run-make/lto-linkage-used-attr/Makefile
-run-make/lto-no-link-whole-rlib/Makefile
 run-make/macos-deployment-target/Makefile
 run-make/min-global-align/Makefile
 run-make/native-link-modifier-bundle/Makefile
@@ -65,7 +52,6 @@ run-make/no-alloc-shim/Makefile
 run-make/no-builtins-attribute/Makefile
 run-make/no-duplicate-libs/Makefile
 run-make/panic-abort-eh_frame/Makefile
-run-make/pass-non-c-like-enum-to-c/Makefile
 run-make/pdb-buildinfo-cl-cmd/Makefile
 run-make/pgo-gen-lto/Makefile
 run-make/pgo-gen-no-imp-symbols/Makefile
@@ -82,9 +68,7 @@ run-make/redundant-libs/Makefile
 run-make/remap-path-prefix-dwarf/Makefile
 run-make/reproducible-build-2/Makefile
 run-make/reproducible-build/Makefile
-run-make/return-non-c-like-enum-from-c/Makefile
 run-make/rlib-format-packed-bundled-libs-2/Makefile
-run-make/rlib-format-packed-bundled-libs-3/Makefile
 run-make/rlib-format-packed-bundled-libs/Makefile
 run-make/sanitizer-cdylib-link/Makefile
 run-make/sanitizer-dylib-link/Makefile
@@ -94,12 +78,10 @@ run-make/simd-ffi/Makefile
 run-make/split-debuginfo/Makefile
 run-make/stable-symbol-names/Makefile
 run-make/static-dylib-by-default/Makefile
-run-make/staticlib-blank-lib/Makefile
 run-make/staticlib-dylib-linkage/Makefile
 run-make/symbol-mangling-hashed/Makefile
 run-make/symbol-visibility/Makefile
 run-make/sysroot-crates-are-unstable/Makefile
-run-make/test-benches/Makefile
 run-make/thumb-none-cortex-m/Makefile
 run-make/thumb-none-qemu/Makefile
 run-make/translation/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index f9bf04626f7..ea03662c584 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -65,11 +65,12 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>)
     //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo
     ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None),
     ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None),
-    //("src/etc/test-float-parse", &[], None), // FIXME uncomment once all deps are vendored
+    ("src/etc/test-float-parse", EXCEPTIONS, None),
     ("src/tools/cargo", EXCEPTIONS_CARGO, None),
     //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
     //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
     ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None),
+    ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None),
     ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None),
     ("src/tools/x", &[], None),
     // tidy-alphabetical-end
@@ -167,6 +168,13 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[
     // tidy-alphabetical-end
 ];
 
+const EXCEPTIONS_RUSTBOOK: ExceptionList = &[
+    // tidy-alphabetical-start
+    ("mdbook", "MPL-2.0"),
+    ("ryu", "Apache-2.0 OR BSL-1.0"),
+    // tidy-alphabetical-end
+];
+
 const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     // tidy-alphabetical-start
     ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
diff --git a/src/version b/src/version
index dbd41264aa9..71fae54fb27 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.81.0
+1.82.0
diff --git a/tests/codegen/generic-debug.rs b/tests/codegen/generic-debug.rs
index 3423abe7187..0ad0b074657 100644
--- a/tests/codegen/generic-debug.rs
+++ b/tests/codegen/generic-debug.rs
@@ -1,4 +1,3 @@
-//@ ignore-windows
 //@ ignore-wasi wasi codegens the main symbol differently
 
 //@ compile-flags: -g -C no-prepopulate-passes
diff --git a/tests/codegen/issues/issue-58881.rs b/tests/codegen/issues/issue-58881.rs
index 759e3b70baa..ba6285f3972 100644
--- a/tests/codegen/issues/issue-58881.rs
+++ b/tests/codegen/issues/issue-58881.rs
@@ -1,7 +1,6 @@
 //@ compile-flags: -C no-prepopulate-passes -Copt-level=0
 //
 //@ only-x86_64
-//@ ignore-windows
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/mainsubprogram.rs b/tests/codegen/mainsubprogram.rs
index 12b24c90229..ce3fe3c8608 100644
--- a/tests/codegen/mainsubprogram.rs
+++ b/tests/codegen/mainsubprogram.rs
@@ -1,7 +1,6 @@
 // This test depends on a patch that was committed to upstream LLVM
 // before 4.0, formerly backported to the Rust LLVM fork.
 
-//@ ignore-windows
 //@ ignore-apple
 //@ ignore-wasi
 
diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs
index 20741791db5..0bcb311644d 100644
--- a/tests/codegen/mainsubprogramstart.rs
+++ b/tests/codegen/mainsubprogramstart.rs
@@ -1,4 +1,3 @@
-//@ ignore-windows
 //@ ignore-apple
 //@ ignore-wasi wasi codegens the main symbol differently
 
diff --git a/tests/codegen/nounwind.rs b/tests/codegen/nounwind.rs
index 464bc2535c2..c910644458a 100644
--- a/tests/codegen/nounwind.rs
+++ b/tests/codegen/nounwind.rs
@@ -1,6 +1,5 @@
 //@ aux-build:nounwind.rs
 //@ compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a
-//@ ignore-windows
 //@ ignore-android
 
 #![crate_type = "lib"]
diff --git a/tests/crashes/119299.rs b/tests/crashes/119299.rs
deleted file mode 100644
index c8c10546d94..00000000000
--- a/tests/crashes/119299.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//@ known-bug: #119299
-#![feature(adt_const_params)]
-#![allow(incomplete_features)]
-
-use std::marker::ConstParamTy;
-
-#[derive(Eq, PartialEq)]
-struct ConstStrU(*const u8, usize);
-
-impl ConstParamTy for &'static ConstStrU {}
-
-impl ConstStrU {
-  const fn from_bytes(bytes: &'static [u8]) -> Self {
-    Self(bytes.as_ptr(), bytes.len())
-  }
-}
-
-const fn chars_s<const S: &'static ConstStrU>() -> [char; 3] {
-  ['a','b','c']
-}
-
-fn main() {
-  const A: &'static ConstStrU = &ConstStrU::from_bytes(b"abc");
-  chars_s::<A>();
-}
diff --git a/tests/crashes/127009.rs b/tests/crashes/127009.rs
deleted file mode 100644
index 74ca14393e4..00000000000
--- a/tests/crashes/127009.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #127009
-
-#![feature(non_lifetime_binders)]
-
-fn b()
-where
-    for<const C: usize> [(); C]: Copy,
-{
-}
-
-fn main() {}
diff --git a/tests/crashes/127351.rs b/tests/crashes/127351.rs
new file mode 100644
index 00000000000..e3f41594885
--- /dev/null
+++ b/tests/crashes/127351.rs
@@ -0,0 +1,17 @@
+//@ known-bug: #127351
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+struct Outer0<'a, T>(ExplicitTypeOutlives<'a, T>);
+type ExplicitTypeOutlives<'a, T: 'a> = (&'a (), T);
+
+pub struct Warns {
+    _significant_drop: ExplicitTypeOutlives,
+    field: String,
+}
+
+pub fn test(w: Warns) {
+    _ = || drop(w.field);
+}
+
+fn main() {}
diff --git a/tests/crashes/127353.rs b/tests/crashes/127353.rs
new file mode 100644
index 00000000000..9bcb90b5c57
--- /dev/null
+++ b/tests/crashes/127353.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #127353
+#![feature(type_alias_impl_trait)]
+trait Trait<T> {}
+type Alias<'a, U> = impl Trait<U>;
+
+fn f<'a>() -> Alias<'a, ()> {}
+
+pub enum UninhabitedVariants {
+    Tuple(Alias),
+}
+
+struct A;
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {}
+}
+
+fn main() {}
diff --git a/tests/crashes/127628.rs b/tests/crashes/127628.rs
new file mode 100644
index 00000000000..f11ab3f7e8d
--- /dev/null
+++ b/tests/crashes/127628.rs
@@ -0,0 +1,14 @@
+//@ known-bug: #127628
+//@ compile-flags: -Zpolonius=next
+
+use std::io::{self, Read};
+
+pub struct Container<'a> {
+    reader: &'a mut dyn Read,
+}
+
+impl<'a> Container {
+    pub fn wrap<'s>(reader: &'s mut dyn io::Read) -> Container<'s> {
+        Container { reader: reader }
+    }
+}
diff --git a/tests/crashes/127643.rs b/tests/crashes/127643.rs
new file mode 100644
index 00000000000..a4db9397bde
--- /dev/null
+++ b/tests/crashes/127643.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #127643
+
+#![feature(associated_const_equality)]
+
+fn user() -> impl Owner<dyn Sized, C = 0> {}
+
+trait Owner<K> {
+    const C: K;
+}
+impl<K: ConstDefault> Owner<K> for () {
+    const C: K = K::DEFAULT;
+}
+
+trait ConstDefault {
+    const DEFAULT: Self;
+}
+
+fn main() {}
diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs
new file mode 100644
index 00000000000..81149c2ef84
--- /dev/null
+++ b/tests/crashes/127676.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #127676
+//@ edition:2018
+
+#![feature(dyn_star,const_async_blocks)]
+
+static S: dyn* Send + Sync = async { 42 };
+
+pub fn main() {}
diff --git a/tests/crashes/127737.rs b/tests/crashes/127737.rs
new file mode 100644
index 00000000000..2ee8c769858
--- /dev/null
+++ b/tests/crashes/127737.rs
@@ -0,0 +1,21 @@
+//@ known-bug: #127737
+//@ compile-flags: -Zmir-opt-level=5 --crate-type lib
+
+pub trait TestTrait {
+    type MyType;
+    fn func() -> Option<Self>
+    where
+        Self: Sized;
+}
+
+impl<T> dyn TestTrait<MyType = T>
+where
+    Self: Sized,
+{
+    pub fn other_func() -> Option<Self> {
+        match Self::func() {
+            Some(me) => Some(me),
+            None => None,
+        }
+    }
+}
diff --git a/tests/crashes/127742.rs b/tests/crashes/127742.rs
new file mode 100644
index 00000000000..24add454135
--- /dev/null
+++ b/tests/crashes/127742.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #127742
+struct Vtable(dyn Cap);  // missing lifetime
+
+trait Cap<'a> {}
+
+union Transmute {
+    t: u64,  // ICEs with u64, u128, or usize. Correctly errors with u32.
+    u: &'static Vtable,
+}
+
+const G: &'static Vtable = unsafe { Transmute { t: 1 }.u };
diff --git a/tests/crashes/127880.rs b/tests/crashes/127880.rs
new file mode 100644
index 00000000000..6c625eac691
--- /dev/null
+++ b/tests/crashes/127880.rs
@@ -0,0 +1,5 @@
+//@ known-bug: #127880
+//@ compile-flags: -Cinstrument-coverage
+
+#[coverage]
+fn main() {}
diff --git a/tests/crashes/127916.rs b/tests/crashes/127916.rs
new file mode 100644
index 00000000000..295c88df857
--- /dev/null
+++ b/tests/crashes/127916.rs
@@ -0,0 +1,16 @@
+//@ known-bug: #127916
+
+trait Trait {
+    fn foo(&self) -> u32 { 0 }
+}
+
+struct F;
+struct S;
+
+mod to_reuse {
+    pub fn foo(&self) -> u32 {}
+}
+
+impl Trait  S {
+    reuse to_reuse::foo { self }
+}
diff --git a/tests/crashes/127972.rs b/tests/crashes/127972.rs
new file mode 100644
index 00000000000..d0764f875db
--- /dev/null
+++ b/tests/crashes/127972.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #127962
+#![feature(generic_const_exprs)]
+
+fn zero_init<const usize: usize>() -> Substs1<{ (N) }> {
+    Substs1([0; { (usize) }])
+}
diff --git a/tests/crashes/128016.rs b/tests/crashes/128016.rs
new file mode 100644
index 00000000000..d23721ae14e
--- /dev/null
+++ b/tests/crashes/128016.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #128016
+macro_rules! len {
+    () => {
+        target
+    };
+}
+
+fn main() {
+    let val: [str; len!()] = [];
+}
diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs
index 91ee36ae2c5..b59103792bf 100644
--- a/tests/mir-opt/const_prop/invalid_constant.rs
+++ b/tests/mir-opt/const_prop/invalid_constant.rs
@@ -3,7 +3,7 @@
 //@ compile-flags: -Zmir-enable-passes=+RemoveZsts
 // Verify that we can pretty print invalid constants.
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 #[derive(Copy, Clone)]
diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff
index 1aeaaff21dc..3b739a25cb8 100644
--- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff
@@ -57,9 +57,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     05 00 00 00 03 00 00 00                         │ ........
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs
index aca5f047222..9cd485813bc 100644
--- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs
+++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs
@@ -1,6 +1,7 @@
 //! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning
 //! the contained scalars.
 //@ test-mir-pass: DataflowConstProp
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 
 const Foo: (u32, u32) = (5, 3);
 
diff --git a/tests/mir-opt/issue_99325.rs b/tests/mir-opt/issue_99325.rs
index 2638b69e2ee..4cee4f20b31 100644
--- a/tests/mir-opt/issue_99325.rs
+++ b/tests/mir-opt/issue_99325.rs
@@ -1,7 +1,7 @@
 // skip-filecheck
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
diff --git a/tests/run-make/c-static-dylib/Makefile b/tests/run-make/c-static-dylib/Makefile
deleted file mode 100644
index 05da1743c83..00000000000
--- a/tests/run-make/c-static-dylib/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# This test checks that static Rust linking with C does not encounter any errors, with dynamic dependencies given preference over static.
-# See https://github.com/rust-lang/rust/issues/10434
-
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,cfoo)
-	$(RUSTC) foo.rs -C prefer-dynamic
-	$(RUSTC) bar.rs
-	rm $(call NATIVE_STATICLIB,cfoo)
-	$(call RUN,bar)
-	$(call REMOVE_DYLIBS,foo)
-	$(call FAIL,bar)
diff --git a/tests/run-make/c-static-dylib/rmake.rs b/tests/run-make/c-static-dylib/rmake.rs
new file mode 100644
index 00000000000..12ec06c8199
--- /dev/null
+++ b/tests/run-make/c-static-dylib/rmake.rs
@@ -0,0 +1,20 @@
+// This test checks that static Rust linking with C does not encounter any errors,
+// with dynamic dependencies given preference over static.
+// See https://github.com/rust-lang/rust/issues/10434
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{
+    build_native_static_lib, dynamic_lib_name, rfs, run, run_fail, rustc, static_lib_name,
+};
+
+fn main() {
+    build_native_static_lib("cfoo");
+    rustc().input("foo.rs").arg("-Cprefer-dynamic").run();
+    rustc().input("bar.rs").run();
+    rfs::remove_file(static_lib_name("cfoo"));
+    run("bar");
+    rfs::remove_file(dynamic_lib_name("foo"));
+    run_fail("bar");
+}
diff --git a/tests/run-make/c-static-rlib/Makefile b/tests/run-make/c-static-rlib/Makefile
deleted file mode 100644
index 298e432cdb8..00000000000
--- a/tests/run-make/c-static-rlib/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# This test checks that static Rust linking with C does not encounter any errors, with static dependencies given preference over dynamic. (This is the default behaviour.)
-# See https://github.com/rust-lang/rust/issues/10434
-
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,cfoo)
-	$(RUSTC) foo.rs
-	$(RUSTC) bar.rs
-	$(call REMOVE_RLIBS,foo)
-	rm $(call NATIVE_STATICLIB,cfoo)
-	$(call RUN,bar)
diff --git a/tests/run-make/c-static-rlib/rmake.rs b/tests/run-make/c-static-rlib/rmake.rs
new file mode 100644
index 00000000000..447e29a14f6
--- /dev/null
+++ b/tests/run-make/c-static-rlib/rmake.rs
@@ -0,0 +1,17 @@
+// This test checks that static Rust linking with C does not encounter any errors,
+// with static dependencies given preference over dynamic. (This is the default behaviour.)
+// See https://github.com/rust-lang/rust/issues/10434
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, rfs, run, rust_lib_name, rustc, static_lib_name};
+
+fn main() {
+    build_native_static_lib("cfoo");
+    rustc().input("foo.rs").run();
+    rustc().input("bar.rs").run();
+    rfs::remove_file(rust_lib_name("foo"));
+    rfs::remove_file(static_lib_name("cfoo"));
+    run("bar");
+}
diff --git a/tests/run-make/c-unwind-abi-catch-panic/Makefile b/tests/run-make/c-unwind-abi-catch-panic/Makefile
deleted file mode 100644
index 0a38d838e32..00000000000
--- a/tests/run-make/c-unwind-abi-catch-panic/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# Exercise unwinding a panic. This catches a panic across an FFI boundary and downcasts it into an integer. The Rust code that panics is in the same directory.
-# See https://github.com/rust-lang/rust/commit/baf227ea0c1e07fc54395a51e4b3881d701180cb
-
-# ignore-cross-compile
-# needs-unwind
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,add)
-	$(RUSTC) main.rs
-	$(call RUN,main) || exit 1
diff --git a/tests/run-make/c-unwind-abi-catch-panic/rmake.rs b/tests/run-make/c-unwind-abi-catch-panic/rmake.rs
new file mode 100644
index 00000000000..a99dbd18ec6
--- /dev/null
+++ b/tests/run-make/c-unwind-abi-catch-panic/rmake.rs
@@ -0,0 +1,18 @@
+// A test for calling `C-unwind` functions across foreign function boundaries (FFI).
+// This test triggers a panic when calling a foreign function that calls *back* into Rust.
+// This catches a panic across an FFI boundary and downcasts it into an integer.
+// The Rust code that panics is in the same directory, unlike `c-unwind-abi-catch-lib-panic`.
+// See https://github.com/rust-lang/rust/pull/76570
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+//@ needs-unwind
+// Reason: this test exercises panic unwinding
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("add");
+    rustc().input("main.rs").run();
+    run("main");
+}
diff --git a/tests/run-make/compiler-lookup-paths-2/Makefile b/tests/run-make/compiler-lookup-paths-2/Makefile
deleted file mode 100644
index ecc0577384a..00000000000
--- a/tests/run-make/compiler-lookup-paths-2/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# This test checks that extern crate declarations in Cargo without a corresponding declaration in the manifest of a dependency are NOT allowed.
-# See https://github.com/rust-lang/rust/pull/21113
-
-include ../tools.mk
-
-all:
-	mkdir -p $(TMPDIR)/a $(TMPDIR)/b
-	$(RUSTC) a.rs && mv $(TMPDIR)/liba.rlib $(TMPDIR)/a
-	$(RUSTC) b.rs -L $(TMPDIR)/a && mv $(TMPDIR)/libb.rlib $(TMPDIR)/b
-	$(RUSTC) c.rs -L crate=$(TMPDIR)/b -L dependency=$(TMPDIR)/a \
-		&& exit 1 || exit 0
diff --git a/tests/run-make/compiler-lookup-paths-2/rmake.rs b/tests/run-make/compiler-lookup-paths-2/rmake.rs
new file mode 100644
index 00000000000..99efb157b53
--- /dev/null
+++ b/tests/run-make/compiler-lookup-paths-2/rmake.rs
@@ -0,0 +1,20 @@
+// This test checks that extern crate declarations in Cargo without a corresponding declaration
+// in the manifest of a dependency are NOT allowed. The last rustc call does it anyways, which
+// should result in a compilation failure.
+// See https://github.com/rust-lang/rust/pull/21113
+
+use run_make_support::{path, rfs, rust_lib_name, rustc};
+
+fn main() {
+    rfs::create_dir("a");
+    rfs::create_dir("b");
+    rustc().input("a.rs").run();
+    rfs::rename(rust_lib_name("a"), path("a").join(rust_lib_name("a")));
+    rustc().input("b.rs").library_search_path("a").run();
+    rfs::rename(rust_lib_name("b"), path("b").join(rust_lib_name("b")));
+    rustc()
+        .input("c.rs")
+        .library_search_path("crate=b")
+        .library_search_path("dependency=a")
+        .run_fail();
+}
diff --git a/tests/run-make/extern-fn-generic/Makefile b/tests/run-make/extern-fn-generic/Makefile
deleted file mode 100644
index 7dceea6cb88..00000000000
--- a/tests/run-make/extern-fn-generic/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,test)
-	$(RUSTC) testcrate.rs
-	$(RUSTC) test.rs
-	$(call RUN,test) || exit 1
diff --git a/tests/run-make/extern-fn-generic/rmake.rs b/tests/run-make/extern-fn-generic/rmake.rs
new file mode 100644
index 00000000000..05de839a1b0
--- /dev/null
+++ b/tests/run-make/extern-fn-generic/rmake.rs
@@ -0,0 +1,16 @@
+// Generic types in foreign-function interfaces were introduced in #15831 - this
+// test simply runs a Rust program containing generics that is also reliant on
+// a C library, and checks that compilation and execution are successful.
+// See https://github.com/rust-lang/rust/pull/15831
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("test");
+    rustc().input("testcrate.rs").run();
+    rustc().input("test.rs").run();
+    run("test");
+}
diff --git a/tests/run-make/extern-fn-with-union/Makefile b/tests/run-make/extern-fn-with-union/Makefile
deleted file mode 100644
index e6c8c993679..00000000000
--- a/tests/run-make/extern-fn-with-union/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,ctest)
-	$(RUSTC) testcrate.rs
-	$(RUSTC) test.rs
-	$(call RUN,test) || exit 1
diff --git a/tests/run-make/extern-fn-with-union/rmake.rs b/tests/run-make/extern-fn-with-union/rmake.rs
new file mode 100644
index 00000000000..200602eabeb
--- /dev/null
+++ b/tests/run-make/extern-fn-with-union/rmake.rs
@@ -0,0 +1,16 @@
+// If an external function from foreign-function interface was called upon,
+// its attributes would only be passed to LLVM if and only if it was called in the same crate.
+// This caused passing around unions to be incorrect.
+// See https://github.com/rust-lang/rust/pull/14191
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("ctest");
+    rustc().input("testcrate.rs").run();
+    rustc().input("test.rs").run();
+    run("test");
+}
diff --git a/tests/run-make/issue-14698/foo.rs b/tests/run-make/invalid-tmpdir-env-var/foo.rs
index f328e4d9d04..f328e4d9d04 100644
--- a/tests/run-make/issue-14698/foo.rs
+++ b/tests/run-make/invalid-tmpdir-env-var/foo.rs
diff --git a/tests/run-make/invalid-tmpdir-env-var/rmake.rs b/tests/run-make/invalid-tmpdir-env-var/rmake.rs
new file mode 100644
index 00000000000..db44debb319
--- /dev/null
+++ b/tests/run-make/invalid-tmpdir-env-var/rmake.rs
@@ -0,0 +1,20 @@
+// When the TMP (on Windows) or TMPDIR (on Unix) variable is set to an invalid
+// or non-existing directory, this used to cause an internal compiler error (ICE). After the
+// addition of proper error handling in #28430, this test checks that the expected message is
+// printed.
+// See https://github.com/rust-lang/rust/issues/14698
+
+use run_make_support::{is_windows, rustc};
+
+// NOTE: This is not a UI test despite its simplicity, as the error message contains a path
+// with some variability that is difficult to normalize
+
+fn main() {
+    let mut rustc = rustc();
+    if is_windows() {
+        rustc.env("TMP", "fake");
+    } else {
+        rustc.env("TMPDIR", "fake");
+    }
+    rustc.input("foo.rs").run_fail().assert_stderr_contains("couldn't create a temp dir");
+}
diff --git a/tests/run-make/issue-107094/Makefile b/tests/run-make/issue-107094/Makefile
deleted file mode 100644
index d614e3e1055..00000000000
--- a/tests/run-make/issue-107094/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# needs-git-hash
-
-include ../tools.mk
-
-all:
-	$(BARE_RUSTC) --version --verbose | $(CGREP) -i -e "commit-hash: [0-9a-f]{40}" "commit-date: [0-9]{4}-[0-9]{2}-[0-9]{2}"
-	$(BARE_RUSTDOC) --version --verbose | $(CGREP) -i -e "commit-hash: [0-9a-f]{40}" "commit-date: [0-9]{4}-[0-9]{2}-[0-9]{2}"
diff --git a/tests/run-make/issue-14698/Makefile b/tests/run-make/issue-14698/Makefile
deleted file mode 100644
index a1cfb5abab5..00000000000
--- a/tests/run-make/issue-14698/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	TMP=fake TMPDIR=fake $(RUSTC) foo.rs 2>&1 | $(CGREP) "couldn't create a temp dir:"
diff --git a/tests/run-make/issue-28595/Makefile b/tests/run-make/issue-28595/Makefile
deleted file mode 100644
index 258f9788aaf..00000000000
--- a/tests/run-make/issue-28595/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,a) $(call NATIVE_STATICLIB,b)
-	$(RUSTC) a.rs
-	$(RUSTC) b.rs
-	$(call RUN,b)
diff --git a/tests/run-make/issue-33329/Makefile b/tests/run-make/issue-33329/Makefile
deleted file mode 100644
index 9c149440d8e..00000000000
--- a/tests/run-make/issue-33329/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) --target x86_64_unknown-linux-musl main.rs 2>&1 | $(CGREP) \
-		"error: Error loading target specification: Could not find specification for target"
diff --git a/tests/run-make/issue-33329/main.rs b/tests/run-make/issue-33329/main.rs
deleted file mode 100644
index f328e4d9d04..00000000000
--- a/tests/run-make/issue-33329/main.rs
+++ /dev/null
@@ -1 +0,0 @@
-fn main() {}
diff --git a/tests/run-make/issue-97463-abi-param-passing/Makefile b/tests/run-make/issue-97463-abi-param-passing/Makefile
deleted file mode 100644
index 7ce7aaeec57..00000000000
--- a/tests/run-make/issue-97463-abi-param-passing/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# ignore-msvc
-
-# The issue exercised by this test, rust-lang/rust#97463, explicitly needs `-O`
-# flags (like `-O3`) to reproduce. Thus, we call $(CC) instead of nicer
-# alternatives provided by tools.mk like using `COMPILE_OBJ` or using a
-# `NATIVE_STATICLIB` dependency.
-
-all:
-	$(CC) -c -O3 -o $(TMPDIR)/bad.o bad.c
-	$(AR) rcs $(TMPDIR)/libbad.a $(TMPDIR)/bad.o
-	$(RUSTC) param_passing.rs -L$(TMPDIR) -lbad -C opt-level=3
-	$(call RUN,param_passing)
diff --git a/tests/run-make/linkage-attr-on-static/Makefile b/tests/run-make/linkage-attr-on-static/Makefile
deleted file mode 100644
index ef50a7ef9f1..00000000000
--- a/tests/run-make/linkage-attr-on-static/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,foo)
-	$(RUSTC) bar.rs
-	$(call RUN,bar) || exit 1
diff --git a/tests/run-make/linkage-attr-on-static/rmake.rs b/tests/run-make/linkage-attr-on-static/rmake.rs
new file mode 100644
index 00000000000..cd85542e958
--- /dev/null
+++ b/tests/run-make/linkage-attr-on-static/rmake.rs
@@ -0,0 +1,15 @@
+// #[linkage] is a useful attribute which can be applied to statics to allow
+// external linkage, something which was not possible before #18890. This test
+// checks that using this new feature results in successful compilation and execution.
+// See https://github.com/rust-lang/rust/pull/18890
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("foo");
+    rustc().input("bar.rs").run();
+    run("bar");
+}
diff --git a/tests/run-make/lto-no-link-whole-rlib/Makefile b/tests/run-make/lto-no-link-whole-rlib/Makefile
deleted file mode 100644
index 3e82322e72d..00000000000
--- a/tests/run-make/lto-no-link-whole-rlib/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar)
-	$(RUSTC) lib1.rs
-	$(RUSTC) lib2.rs
-	$(RUSTC) main.rs -Clto
-	$(call RUN,main)
-
diff --git a/tests/run-make/lto-no-link-whole-rlib/rmake.rs b/tests/run-make/lto-no-link-whole-rlib/rmake.rs
new file mode 100644
index 00000000000..8cd653d5f08
--- /dev/null
+++ b/tests/run-make/lto-no-link-whole-rlib/rmake.rs
@@ -0,0 +1,18 @@
+// In order to improve linking performance, entire rlibs will only be linked if a dylib is being
+// created. Otherwise, an executable will only link one rlib as usual. Linking will fail in this
+// test should this optimization be reverted.
+// See https://github.com/rust-lang/rust/pull/31460
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("foo");
+    build_native_static_lib("bar");
+    rustc().input("lib1.rs").run();
+    rustc().input("lib2.rs").run();
+    rustc().input("main.rs").arg("-Clto").run();
+    run("main");
+}
diff --git a/tests/run-make/issue-28595/a.c b/tests/run-make/native-lib-load-order/a.c
index 7bfd83cca21..7bfd83cca21 100644
--- a/tests/run-make/issue-28595/a.c
+++ b/tests/run-make/native-lib-load-order/a.c
diff --git a/tests/run-make/issue-28595/a.rs b/tests/run-make/native-lib-load-order/a.rs
index 07863cf64d6..07863cf64d6 100644
--- a/tests/run-make/issue-28595/a.rs
+++ b/tests/run-make/native-lib-load-order/a.rs
diff --git a/tests/run-make/issue-28595/b.c b/tests/run-make/native-lib-load-order/b.c
index 6aecb5f9e04..6aecb5f9e04 100644
--- a/tests/run-make/issue-28595/b.c
+++ b/tests/run-make/native-lib-load-order/b.c
diff --git a/tests/run-make/issue-28595/b.rs b/tests/run-make/native-lib-load-order/b.rs
index 1f389859fad..1f389859fad 100644
--- a/tests/run-make/issue-28595/b.rs
+++ b/tests/run-make/native-lib-load-order/b.rs
diff --git a/tests/run-make/native-lib-load-order/rmake.rs b/tests/run-make/native-lib-load-order/rmake.rs
new file mode 100644
index 00000000000..ffe20a64168
--- /dev/null
+++ b/tests/run-make/native-lib-load-order/rmake.rs
@@ -0,0 +1,16 @@
+// An old compiler bug from 2015 caused native libraries to be loaded in the
+// wrong order, causing `b` to be loaded before `a` in this test. If the compilation
+// is successful, the libraries were loaded in the correct order.
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("a");
+    build_native_static_lib("b");
+    rustc().input("a.rs").run();
+    rustc().input("b.rs").run();
+    run("b");
+}
diff --git a/tests/run-make/pass-non-c-like-enum-to-c/Makefile b/tests/run-make/pass-non-c-like-enum-to-c/Makefile
deleted file mode 100644
index bd441d321bf..00000000000
--- a/tests/run-make/pass-non-c-like-enum-to-c/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,test)
-	$(RUSTC) nonclike.rs -L$(TMPDIR) -ltest
-	$(call RUN,nonclike)
diff --git a/tests/run-make/pass-non-c-like-enum-to-c/rmake.rs b/tests/run-make/pass-non-c-like-enum-to-c/rmake.rs
new file mode 100644
index 00000000000..c706e82f4a0
--- /dev/null
+++ b/tests/run-make/pass-non-c-like-enum-to-c/rmake.rs
@@ -0,0 +1,19 @@
+// Similar to the `return-non-c-like-enum-from-c` test, where
+// the C code is the library, and the Rust code compiles
+// into the executable. Once again, enum variants should be treated
+// like an union of structs, which should prevent segfaults or
+// unexpected results. The only difference with the aforementioned
+// test is that the structs are passed into C directly through the
+// `tt_add` and `t_add` function calls.
+// See https://github.com/rust-lang/rust/issues/68190
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("test");
+    rustc().input("nonclike.rs").arg("-ltest").run();
+    run("nonclike");
+}
diff --git a/tests/run-make/return-non-c-like-enum-from-c/Makefile b/tests/run-make/return-non-c-like-enum-from-c/Makefile
deleted file mode 100644
index bd441d321bf..00000000000
--- a/tests/run-make/return-non-c-like-enum-from-c/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call NATIVE_STATICLIB,test)
-	$(RUSTC) nonclike.rs -L$(TMPDIR) -ltest
-	$(call RUN,nonclike)
diff --git a/tests/run-make/return-non-c-like-enum-from-c/rmake.rs b/tests/run-make/return-non-c-like-enum-from-c/rmake.rs
new file mode 100644
index 00000000000..f24bd6d5fc7
--- /dev/null
+++ b/tests/run-make/return-non-c-like-enum-from-c/rmake.rs
@@ -0,0 +1,17 @@
+// A reversed version of the `return-non-c-like-enum` test, though
+// this time, the C code is the library, and the Rust code compiles
+// into the executable. Once again, enum variants should be treated
+// like an union of structs, which should prevent segfaults or
+// unexpected results.
+// See https://github.com/rust-lang/rust/issues/68190
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_static_lib("test");
+    rustc().input("nonclike.rs").arg("-ltest").run();
+    run("nonclike");
+}
diff --git a/tests/run-make/rlib-format-packed-bundled-libs-3/Makefile b/tests/run-make/rlib-format-packed-bundled-libs-3/Makefile
deleted file mode 100644
index 9ba077b1854..00000000000
--- a/tests/run-make/rlib-format-packed-bundled-libs-3/Makefile
+++ /dev/null
@@ -1,35 +0,0 @@
-include ../tools.mk
-
-# ignore-cross-compile
-# only-linux
-
-# Make sure -Zpacked_bundled_libs-like behavior activates with +bundle,+whole-archive.
-
-# We're using the llvm-nm instead of the system nm to ensure it is compatible
-# with the LLVM bitcode generated by rustc.
-NM = "$(LLVM_BIN_DIR)"/llvm-nm
-
-all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3) $(call NATIVE_STATICLIB,native_dep_4)
-	# test cfg with packed bundle
-	$(RUSTC) rust_dep_cfg.rs --crate-type=rlib
-	$(RUSTC) main.rs --extern rust_dep=$(TMPDIR)/librust_dep_cfg.rlib --crate-type=staticlib --cfg should_add
-	$(AR) t $(TMPDIR)/librust_dep_cfg.rlib | $(CGREP) -e "libnative_dep_1.a"
-	$(AR) t $(TMPDIR)/librust_dep_cfg.rlib | $(CGREP) -e "libnative_dep_2.a"
-	$(AR) t $(TMPDIR)/libmain.a | $(CGREP) -e "libnative_dep_1.o"
-	$(AR) t $(TMPDIR)/libmain.a | $(CGREP) -ev "libnative_dep_2.o"
-
-
-	# test bundle with whole_archive
-	$(RUSTC) rust_dep.rs --crate-type=rlib
-	$(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -e "native_dep_1"
-	$(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -e "native_dep_3"
-	$(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -ev "native_dep_2"
-	$(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -ev "native_dep_4"
-
-	# Make sure compiler doesn't use files, that it shouldn't know about.
-	rm $(TMPDIR)/libnative_dep_1.a
-	rm $(TMPDIR)/libnative_dep_3.a
-
-	$(RUSTC) main.rs --extern rust_dep=$(TMPDIR)/librust_dep.rlib --print link-args > $(TMPDIR)/link_args
-	cat $(TMPDIR)/link_args | $(CGREP) -ev "native_dep_3"
-	cat $(TMPDIR)/link_args | $(CGREP) -e "--whole-archive.*native_dep_1.*--whole-archive.*lnative_dep_2.*no-whole-archive.*lnative_dep_4"
diff --git a/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs b/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs
new file mode 100644
index 00000000000..d152047600f
--- /dev/null
+++ b/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs
@@ -0,0 +1,84 @@
+// `-Z packed_bundled_libs` is an unstable rustc flag that makes the compiler
+// only require a native library and no supplementary object files to compile.
+// #105601 made it possible to have this behaviour without an unstable flag by
+// passing +bundle in modifiers, and this test checks that this feature successfully
+// compiles and includes only the static libraries, with no object files.
+// See https://github.com/rust-lang/rust/pull/105601
+
+use run_make_support::{
+    build_native_static_lib, is_msvc, llvm_ar, regex, rfs, rust_lib_name, rustc, static_lib_name,
+};
+
+//@ ignore-cross-compile
+// Reason: Invalid library format (not ELF) causes compilation failure
+// in the final `rustc` call.
+
+//@ only-linux
+// Reason: differences in the native lib compilation process causes differences
+// in the --print link-args output
+
+fn main() {
+    build_native_static_lib("native_dep_1");
+    build_native_static_lib("native_dep_2");
+    build_native_static_lib("native_dep_3");
+    build_native_static_lib("native_dep_4");
+    // Test cfg with packed bundle.
+    rustc().input("rust_dep_cfg.rs").crate_type("rlib").run();
+    rustc()
+        .input("main.rs")
+        .extern_("rust_dep", rust_lib_name("rust_dep_cfg"))
+        .crate_type("staticlib")
+        .cfg("should_add")
+        .run();
+    // Only static libraries should appear, no object files at all.
+    llvm_ar()
+        .arg("t")
+        .arg(rust_lib_name("rust_dep_cfg"))
+        .run()
+        .assert_stdout_contains(static_lib_name("native_dep_1"));
+    llvm_ar()
+        .arg("t")
+        .arg(rust_lib_name("rust_dep_cfg"))
+        .run()
+        .assert_stdout_contains(static_lib_name("native_dep_2"));
+    llvm_ar().arg("t").arg(static_lib_name("main")).run().assert_stdout_contains("native_dep_1.o");
+    llvm_ar()
+        .arg("t")
+        .arg(static_lib_name("main"))
+        .run()
+        .assert_stdout_not_contains("native_dep_2.o");
+
+    // Test bundle with whole archive.
+    rustc().input("rust_dep.rs").crate_type("rlib").run();
+    // Only deps with `+bundle` should appear.
+    llvm_ar().arg("t").arg(rust_lib_name("rust_dep")).run().assert_stdout_contains("native_dep_1");
+    llvm_ar().arg("t").arg(rust_lib_name("rust_dep")).run().assert_stdout_contains("native_dep_3");
+    llvm_ar()
+        .arg("t")
+        .arg(rust_lib_name("rust_dep"))
+        .run()
+        .assert_stdout_not_contains("native_dep_2");
+    llvm_ar()
+        .arg("t")
+        .arg(rust_lib_name("rust_dep"))
+        .run()
+        .assert_stdout_not_contains("native_dep_4");
+
+    // The compiler shouldn't use files which it doesn't know about.
+    rfs::remove_file(static_lib_name("native_dep_1"));
+    rfs::remove_file(static_lib_name("native_dep_3"));
+
+    let out = rustc()
+        .input("main.rs")
+        .extern_("rust_dep", rust_lib_name("rust_dep"))
+        .print("link-args")
+        .run()
+        .assert_stdout_not_contains("native_dep_3")
+        .stdout_utf8();
+
+    let re = regex::Regex::new(
+"--whole-archive.*native_dep_1.*--whole-archive.*lnative_dep_2.*no-whole-archive.*lnative_dep_4"
+    ).unwrap();
+
+    assert!(re.is_match(&out));
+}
diff --git a/tests/run-make/staticlib-blank-lib/Makefile b/tests/run-make/staticlib-blank-lib/Makefile
deleted file mode 100644
index fcbf87758fb..00000000000
--- a/tests/run-make/staticlib-blank-lib/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-include ../tools.mk
-
-all:
-	$(AR) crus $(TMPDIR)/libfoo.a foo.rs
-	$(AR) d $(TMPDIR)/libfoo.a foo.rs
-	$(RUSTC) foo.rs
diff --git a/tests/run-make/staticlib-blank-lib/rmake.rs b/tests/run-make/staticlib-blank-lib/rmake.rs
new file mode 100644
index 00000000000..11a85d102aa
--- /dev/null
+++ b/tests/run-make/staticlib-blank-lib/rmake.rs
@@ -0,0 +1,13 @@
+// In this test, the static library foo is made blank, which used to cause
+// a compilation error. As the compiler now returns Ok upon encountering a blank
+// staticlib as of #12379, this test checks that compilation is successful despite
+// the blank staticlib.
+// See https://github.com/rust-lang/rust/pull/12379
+
+use run_make_support::{llvm_ar, rustc, static_lib_name};
+
+fn main() {
+    llvm_ar().obj_to_ar().output_input(static_lib_name("foo"), "foo.rs").run();
+    llvm_ar().arg("d").output_input(static_lib_name("foo"), "foo.rs").run();
+    rustc().input("foo.rs").run();
+}
diff --git a/tests/run-make/test-benches/Makefile b/tests/run-make/test-benches/Makefile
deleted file mode 100644
index 11aed2e4c79..00000000000
--- a/tests/run-make/test-benches/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-# ignore-cross-compile
-# needs-unwind #[bench] and -Zpanic-abort-tests can't be combined
-
-all:
-	# Smoke-test that `#[bench]` isn't entirely broken.
-	$(RUSTC) --test smokebench.rs -O
-	$(call RUN,smokebench --bench)
-	$(call RUN,smokebench --bench noiter)
-	$(call RUN,smokebench --bench yesiter)
-	$(call RUN,smokebench)
diff --git a/tests/run-make/test-benches/rmake.rs b/tests/run-make/test-benches/rmake.rs
new file mode 100644
index 00000000000..1458fb8c990
--- /dev/null
+++ b/tests/run-make/test-benches/rmake.rs
@@ -0,0 +1,22 @@
+// #[bench] is a Rust feature to run benchmarks on performance-critical
+// code, which previously experienced a runtime panic bug in #103794.
+// In order to ensure future breakages of this feature are detected, this
+// smoke test was created, using the benchmarking feature with various
+// runtime flags.
+// See https://github.com/rust-lang/rust/issues/103794
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+//@ needs-unwind
+// Reason: #[bench] and -Zpanic-abort-tests can't be combined
+
+use run_make_support::{run, run_with_args, rustc};
+
+fn main() {
+    // Smoke-test that #[bench] isn't entirely broken.
+    rustc().arg("--test").input("smokebench.rs").opt().run();
+    run_with_args("smokebench", &["--bench"]);
+    run_with_args("smokebench", &["--bench", "noiter"]);
+    run_with_args("smokebench", &["--bench", "yesiter"]);
+    run("smokebench");
+}
diff --git a/tests/run-make/version-verbose-commit-hash/rmake.rs b/tests/run-make/version-verbose-commit-hash/rmake.rs
new file mode 100644
index 00000000000..733c0e2cdb1
--- /dev/null
+++ b/tests/run-make/version-verbose-commit-hash/rmake.rs
@@ -0,0 +1,20 @@
+// `--version --verbose` should display the git-commit hashes of rustc and rustdoc, but this
+// functionality was lost due to #104184. After this feature was returned by #109981, this
+// test ensures it will not be broken again.
+// See https://github.com/rust-lang/rust/issues/107094
+
+//@ needs-git-hash
+
+use run_make_support::{bare_rustc, bare_rustdoc, regex};
+
+fn main() {
+    let out_rustc =
+        bare_rustc().arg("--version").arg("--verbose").run().stdout_utf8().to_lowercase();
+    let out_rustdoc =
+        bare_rustdoc().arg("--version").arg("--verbose").run().stdout_utf8().to_lowercase();
+    let re =
+        regex::Regex::new(r#"commit-hash: [0-9a-f]{40}\ncommit-date: [0-9]{4}-[0-9]{2}-[0-9]{2}"#)
+            .unwrap();
+    assert!(re.is_match(&out_rustc));
+    assert!(re.is_match(&out_rustdoc));
+}
diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs
index 8d0944ed98d..e69fbac9635 100644
--- a/tests/run-make/wasm-panic-small/rmake.rs
+++ b/tests/run-make/wasm-panic-small/rmake.rs
@@ -13,7 +13,14 @@ fn main() {
 fn test(cfg: &str) {
     eprintln!("running cfg {cfg:?}");
 
-    rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().cfg(cfg).run();
+    rustc()
+        .input("foo.rs")
+        .target("wasm32-wasip1")
+        .arg("-Clto")
+        .arg("-Cstrip=debuginfo")
+        .opt()
+        .cfg(cfg)
+        .run();
 
     let bytes = rfs::read("foo.wasm");
     println!("{}", bytes.len());
diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs
index 93eb38b0987..c0448c59c03 100644
--- a/tests/run-make/wasm-stringify-ints-small/rmake.rs
+++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs
@@ -4,7 +4,13 @@
 use run_make_support::{rfs, rustc};
 
 fn main() {
-    rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run();
+    rustc()
+        .input("foo.rs")
+        .target("wasm32-wasip1")
+        .arg("-Clto")
+        .arg("-Cstrip=debuginfo")
+        .opt()
+        .run();
 
     let bytes = rfs::read("foo.wasm");
     println!("{}", bytes.len());
diff --git a/tests/run-make/issue-97463-abi-param-passing/bad.c b/tests/run-make/zero-extend-abi-param-passing/bad.c
index 013314ab20d..013314ab20d 100644
--- a/tests/run-make/issue-97463-abi-param-passing/bad.c
+++ b/tests/run-make/zero-extend-abi-param-passing/bad.c
diff --git a/tests/run-make/issue-97463-abi-param-passing/param_passing.rs b/tests/run-make/zero-extend-abi-param-passing/param_passing.rs
index c11f3cc72bd..c11f3cc72bd 100644
--- a/tests/run-make/issue-97463-abi-param-passing/param_passing.rs
+++ b/tests/run-make/zero-extend-abi-param-passing/param_passing.rs
diff --git a/tests/run-make/zero-extend-abi-param-passing/rmake.rs b/tests/run-make/zero-extend-abi-param-passing/rmake.rs
new file mode 100644
index 00000000000..aed27f7f5ab
--- /dev/null
+++ b/tests/run-make/zero-extend-abi-param-passing/rmake.rs
@@ -0,0 +1,25 @@
+// This test was created in response to an obscure miscompilation bug, only
+// visible with the -O3 flag passed to the cc compiler when trying to obtain
+// a native static library for the sake of foreign function interface. This
+// flag could cause certain integer types to fail to be zero-extended, resulting
+// in type casting errors. After the fix in #97800, this test attempts integer casting
+// while simultaneously interfacing with a C library and using the -O3 flag.
+// See https://github.com/rust-lang/rust/issues/97463
+
+//@ ignore-msvc
+// Reason: the rustc compilation fails due to an unresolved external symbol
+
+//@ ignore-cross-compile
+// Reason: The compiled binary is executed.
+
+use run_make_support::{cc, is_msvc, llvm_ar, run, rustc, static_lib_name};
+
+fn main() {
+    // The issue exercised by this test specifically needs needs `-O`
+    // flags (like `-O3`) to reproduce. Thus, we call `cc()` instead of
+    // the nicer `build_native_static_lib`.
+    cc().arg("-c").arg("-O3").out_exe("bad.o").input("bad.c").run();
+    llvm_ar().obj_to_ar().output_input(static_lib_name("bad"), "bad.o").run();
+    rustc().input("param_passing.rs").arg("-lbad").opt_level("3").run();
+    run("param_passing");
+}
diff --git a/tests/rustdoc-gui/item-name-wrap.goml b/tests/rustdoc-gui/item-name-wrap.goml
new file mode 100644
index 00000000000..825c16ac5b8
--- /dev/null
+++ b/tests/rustdoc-gui/item-name-wrap.goml
@@ -0,0 +1,23 @@
+// This test ensures that the item name's width is not wrapped.
+go-to: "file://" + |DOC_PATH| + "/test_docs/short_docs/index.html"
+set-window-size: (1000, 600)
+
+// First we ensure that there is only one `item-table`...
+assert-count: ("ul.item-table", 1)
+// And only two items in it.
+assert-count: ("ul.item-table li", 2)
+
+// If they don't have the same height, then it means one of the two is on two lines whereas it
+// shouldn't!
+compare-elements-size: (
+    ".item-table .item-name a[href='fn.mult_vec_num.html']",
+    ".item-table .item-name a[href='fn.subt_vec_num.html']",
+    ["height"],
+)
+
+// We also check that the `item-table` is taking the full width.
+compare-elements-size: (
+    "#functions",
+    "ul.item-table",
+    ["width"],
+)
diff --git a/tests/rustdoc-gui/source-code-page-code-scroll.goml b/tests/rustdoc-gui/source-code-page-code-scroll.goml
index 35f338ea328..31ab281d6ce 100644
--- a/tests/rustdoc-gui/source-code-page-code-scroll.goml
+++ b/tests/rustdoc-gui/source-code-page-code-scroll.goml
@@ -2,7 +2,7 @@
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 set-window-size: (800, 1000)
 // "scrollWidth" should be superior than "clientWidth".
-assert-property: ("body", {"scrollWidth": 1047, "clientWidth": 800})
+assert-property: ("body", {"scrollWidth": 1114, "clientWidth": 800})
 
 // Both properties should be equal (ie, no scroll on the code block).
-assert-property: (".example-wrap .rust", {"scrollWidth": 933, "clientWidth": 933})
+assert-property: (".example-wrap .rust", {"scrollWidth": 1000, "clientWidth": 1000})
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index 7e34178e56f..7397992c0ab 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -20,10 +20,10 @@ Also, stop using `bar` as it's <span class="stab deprecated" title="">deprecated
 Also, stop using `bar` as it's <span class="stab deprecated" title="">deprecated</span>.
 Also, stop using `bar` as it's <span class="stab deprecated" title="">deprecated</span>.
 
-Finally, you can use `quz` only on <span class="stab portability"><code>Unix or x86-64</code>
-</span>.
-Finally, you can use `quz` only on <span class="stab portability"><code>Unix or x86-64</code>
-</span>.
+Finally, you can use `quz` only on <span class="stab portability" data-span="1"><code>Unix or x86-64
+</code></span>.
+Finally, you can use `quz` only on <span class="stab portability" data-span="2"><code>Unix or x86-64
+</code></span>.
 */
 
 use std::convert::AsRef;
@@ -614,3 +614,17 @@ pub mod private {
         B,
     }
 }
+
+pub mod trait_bounds {
+    pub trait OneBound: Sized {}
+    pub trait TwoBounds: Sized + Copy {}
+    pub trait ThreeBounds: Sized + Copy + Eq {}
+}
+
+pub mod short_docs {
+    /// mult_vec_num(x: &[f64], y: f64)
+    pub fn mult_vec_num() {}
+
+    /// subt_vec_num(x: &[f64], y: f64)
+    pub fn subt_vec_num() {}
+}
diff --git a/tests/rustdoc-gui/stab-in-doc.goml b/tests/rustdoc-gui/stab-in-doc.goml
new file mode 100644
index 00000000000..6a03a51fe9f
--- /dev/null
+++ b/tests/rustdoc-gui/stab-in-doc.goml
@@ -0,0 +1,9 @@
+// This test ensure that `stab` elements if used in doc blocks are not breaking the text layout.
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+// We make the window wide enough for the two stabs who are looking into to be on the same line.
+set-window-size: (1100, 600)
+compare-elements-position: (
+    ".top-doc .docblock span[data-span='1']",
+    ".top-doc .docblock span[data-span='2']",
+    ["y"],
+)
diff --git a/tests/rustdoc-gui/trait-with-bounds.goml b/tests/rustdoc-gui/trait-with-bounds.goml
new file mode 100644
index 00000000000..f076bdd4707
--- /dev/null
+++ b/tests/rustdoc-gui/trait-with-bounds.goml
@@ -0,0 +1,35 @@
+// Check that if a trait has more than 2 bounds, they are displayed on different lines.
+
+// It tries to load a JS for each trait but there are none since they're not implemented.
+fail-on-request-error: false
+go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.OneBound.html"
+// They should have the same Y position.
+compare-elements-position: (
+    ".item-decl code",
+    ".item-decl a.trait[title='trait core::marker::Sized']",
+    ["y"],
+)
+go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.TwoBounds.html"
+// They should have the same Y position.
+compare-elements-position: (
+    ".item-decl code",
+    ".item-decl a.trait[title='trait core::marker::Copy']",
+    ["y"],
+)
+go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.ThreeBounds.html"
+// All on their own line.
+compare-elements-position-false: (
+    ".item-decl code",
+    ".item-decl a.trait[title='trait core::marker::Sized']",
+    ["y"],
+)
+compare-elements-position-false: (
+    ".item-decl a.trait[title='trait core::marker::Sized']",
+    ".item-decl a.trait[title='trait core::marker::Copy']",
+    ["y"],
+)
+compare-elements-position-false: (
+    ".item-decl a.trait[title='trait core::marker::Copy']",
+    ".item-decl a.trait[title='trait core::cmp::Eq']",
+    ["y"],
+)
diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml
index fdf84c3fd29..8df946c6f39 100644
--- a/tests/rustdoc-gui/type-declation-overflow.goml
+++ b/tests/rustdoc-gui/type-declation-overflow.goml
@@ -8,34 +8,38 @@ fail-on-request-error: false
 
 go-to: "file://" + |DOC_PATH| + "/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html"
 // We set a fixed size so there is no chance of "random" resize.
-set-window-size: (1100, 800)
+set-window-size: (710, 800)
 // Logically, the <body> scroll width should be the width of the window.
-assert-property: ("body", {"scrollWidth": "1100"})
-// However, since there is overflow in the type declaration, its scroll width is bigger.
-assert-property: ("pre.item-decl", {"scrollWidth": "1324"})
+assert-property: ("body", {"scrollWidth": "710"})
+// We now check that the section width hasn't grown because of it.
+assert-property: ("#main-content", {"scrollWidth": "450"})
+// However, since there is overflow in the type declaration, its scroll width is bigger that "#main-content".
+assert-property: ("pre.item-decl", {"scrollWidth": "585"})
 
 // In the table-ish view on the module index, the name should not be wrapped more than necessary.
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/index.html"
 
 // We'll ensure that items with short documentation have the same width.
 store-property: ("//*[@class='item-table']//*[@class='struct']/..", {"offsetWidth": offset_width})
-assert: |offset_width| == "277"
+assert: |offset_width| == "149"
 assert-property: ("//*[@class='item-table']//*[@class='constant']/..", {"offsetWidth": |offset_width|})
 
 // We now make the same check on type declaration...
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html"
-assert-property: ("body", {"scrollWidth": "1100"})
+assert-property: ("body", {"scrollWidth": "710"})
+// Getting the width of the "<main>" element.
+assert-property: ("main", {"scrollWidth": "510"})
 // We now check that the section width hasn't grown because of it.
-assert-property: ("#main-content", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "450"})
 // And now checking that it has scrollable content.
 assert-property: ("pre.item-decl", {"scrollWidth": "1103"})
 
 // ... and constant.
 // On a sidenote, it also checks that the (very) long title isn't changing the docblock width.
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html"
-assert-property: ("body", {"scrollWidth": "1100"})
+assert-property: ("body", {"scrollWidth": "710"})
 // We now check that the section width hasn't grown because of it.
-assert-property: ("#main-content", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "450"})
 // And now checking that it has scrollable content.
 assert-property: ("pre.item-decl", {"scrollWidth": "950"})
 
diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr
index f7f3e368a3c..3d17570a7a2 100644
--- a/tests/rustdoc-ui/track-diagnostics.stderr
+++ b/tests/rustdoc-ui/track-diagnostics.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL | const S: A = B;
    |              ^ expected `A`, found `B`
--Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC
+-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs b/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs
index 5fa6891b23d..e1f19e7e017 100644
--- a/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs
+++ b/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs
@@ -24,14 +24,14 @@ impl Foo<u32> {
 }
 
 impl<T> Bar for Foo<T> {
-    //@ has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' 'type Item = T'
+    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' 'type Item = T'
     type Item=T;
 
     //@ has - '//*[@id="method.quux"]//h4[@class="code-header"]' 'fn quux(self)'
     fn quux(self) {}
 }
 impl<'a, T> Bar for &'a Foo<T> {
-    //@ has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item = &'a T"
+    // @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item = &'a T"
     type Item=&'a T;
 
     //@ has - '//*[@id="method.quux-1"]//h4[@class="code-header"]' 'fn quux(self)'
diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc/const-generics/const-impl.rs
index ce536291290..279a7842254 100644
--- a/tests/rustdoc/const-generics/const-impl.rs
+++ b/tests/rustdoc/const-generics/const-impl.rs
@@ -1,5 +1,5 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![crate_name = "foo"]
 
 use std::marker::ConstParamTy;
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 00a97ca1488..57cbe173c78 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 197 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 199 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 78b7f0f5d99..764f1c86639 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/closures/binder/const-bound.rs b/tests/ui/closures/binder/const-bound.rs
index b1c79db1375..10d869fcc85 100644
--- a/tests/ui/closures/binder/const-bound.rs
+++ b/tests/ui/closures/binder/const-bound.rs
@@ -3,5 +3,6 @@
 
 fn main()  {
     for<const N: i32> || -> () {};
-    //~^ ERROR late-bound const parameter not allowed on closures
+    //~^ ERROR late-bound const parameters cannot be used currently
+    //~| ERROR late-bound const parameter not allowed on closures
 }
diff --git a/tests/ui/closures/binder/const-bound.stderr b/tests/ui/closures/binder/const-bound.stderr
index 9c4fd95ed76..b805879f7fa 100644
--- a/tests/ui/closures/binder/const-bound.stderr
+++ b/tests/ui/closures/binder/const-bound.stderr
@@ -1,3 +1,9 @@
+error: late-bound const parameters cannot be used currently
+  --> $DIR/const-bound.rs:5:15
+   |
+LL |     for<const N: i32> || -> () {};
+   |               ^
+
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/const-bound.rs:1:37
    |
@@ -13,5 +19,5 @@ error: late-bound const parameter not allowed on closures
 LL |     for<const N: i32> || -> () {};
    |         ^^^^^^^^^^^^
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs
index 6c2a11e0135..f0424e72434 100644
--- a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs
+++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs
@@ -1,13 +1,12 @@
 //@ check-pass
 
-#![feature(adt_const_params)]
-//~^ WARN the feature `adt_const_params` is incomplete
+#![feature(adt_const_params, unsized_const_params)]
+//~^ WARN the feature `unsized_const_params` is incomplete
 #![feature(with_negative_coherence, negative_impls)]
 
 pub trait A<const K: &'static str> {}
 pub trait C {}
 
-
 struct W<T>(T);
 
 // Negative coherence:
diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr
index dc8c926f182..72044915294 100644
--- a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr
+++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr
@@ -1,8 +1,8 @@
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/regions-in-canonical.rs:3:12
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/regions-in-canonical.rs:3:30
    |
-LL | #![feature(adt_const_params)]
-   |            ^^^^^^^^^^^^^^^^
+LL | #![feature(adt_const_params, unsized_const_params)]
+   |                              ^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
    = note: `#[warn(incomplete_features)]` on by default
diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs
index 8035fce0914..e90426ec0c7 100644
--- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs
+++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs
@@ -1,7 +1,6 @@
 //@ check-pass
 #![feature(adt_const_params, lazy_type_alias)]
-//~^ WARN: the feature `adt_const_params` is incomplete
-//~| WARN: the feature `lazy_type_alias` is incomplete
+//~^ WARN: the feature `lazy_type_alias` is incomplete
 
 pub type Matrix = [usize; 1];
 const EMPTY_MATRIX: Matrix = [0; 1];
diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr
index 5c6981077b2..4f5133474c6 100644
--- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr
+++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr
@@ -1,12 +1,3 @@
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/alias_const_param_ty-1.rs:2:12
-   |
-LL | #![feature(adt_const_params, lazy_type_alias)]
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
 warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/alias_const_param_ty-1.rs:2:30
    |
@@ -14,6 +5,7 @@ LL | #![feature(adt_const_params, lazy_type_alias)]
    |                              ^^^^^^^^^^^^^^^
    |
    = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = note: `#[warn(incomplete_features)]` on by default
 
-warning: 2 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs
index a576b75341c..961e1a9cfbf 100644
--- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs
+++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs
@@ -1,6 +1,5 @@
 //@ check-pass
 #![feature(adt_const_params)]
-//~^ WARN: the feature `adt_const_params` is incomplete
 
 const EMPTY_MATRIX: <Type as Trait>::Matrix = [0; 1];
 
diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr
deleted file mode 100644
index dbc8ab71636..00000000000
--- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/alias_const_param_ty-2.rs:2:12
-   |
-LL | #![feature(adt_const_params)]
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs
new file mode 100644
index 00000000000..e2ba459f8dd
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs
@@ -0,0 +1,7 @@
+#![feature(adt_const_params, unsized_const_params)]
+
+#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)]
+pub struct Foo([u8]);
+
+#[derive(std::marker::ConstParamTy, Eq, PartialEq)]
+pub struct GenericNotUnsizedParam<T>(T);
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs
index c4d2d02ba70..35539193a27 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs
@@ -1,13 +1,13 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
-fn check(_: impl std::marker::ConstParamTy) {}
+fn check(_: impl std::marker::UnsizedConstParamTy) {}
 
 fn main() {
-    check(main);               //~ error: `fn() {main}` can't be used as a const parameter type
-    check(|| {});              //~ error: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as a const parameter type
-    check(main as fn());       //~ error: `fn()` can't be used as a const parameter type
-    check(&mut ());            //~ error: `&mut ()` can't be used as a const parameter type
+    check(main); //~ error: `fn() {main}` can't be used as a const parameter type
+    check(|| {}); //~ error: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as a const parameter type
+    check(main as fn()); //~ error: `fn()` can't be used as a const parameter type
+    check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type
     check(&mut () as *mut ()); //~ error: `*mut ()` can't be used as a const parameter type
-    check(&() as *const ());   //~ error: `*const ()` can't be used as a const parameter type
+    check(&() as *const ()); //~ error: `*const ()` can't be used as a const parameter type
 }
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr
index d96491f4f20..694f5a5c1a9 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr
@@ -2,15 +2,15 @@ error[E0277]: `fn() {main}` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad.rs:7:11
    |
 LL |     check(main);
-   |     ----- ^^^^ the trait `ConstParamTy` is not implemented for fn item `fn() {main}`
+   |     ----- ^^^^ the trait `UnsizedConstParamTy` is not implemented for fn item `fn() {main}`
    |     |
    |     required by a bound introduced by this call
    |
 note: required by a bound in `check`
   --> $DIR/const_param_ty_bad.rs:4:18
    |
-LL | fn check(_: impl std::marker::ConstParamTy) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check(_: impl std::marker::UnsizedConstParamTy) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 help: use parentheses to call this function
    |
 LL |     check(main());
@@ -20,15 +20,15 @@ error[E0277]: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as
   --> $DIR/const_param_ty_bad.rs:8:11
    |
 LL |     check(|| {});
-   |     ----- ^^^^^ the trait `ConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}`
+   |     ----- ^^^^^ the trait `UnsizedConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}`
    |     |
    |     required by a bound introduced by this call
    |
 note: required by a bound in `check`
   --> $DIR/const_param_ty_bad.rs:4:18
    |
-LL | fn check(_: impl std::marker::ConstParamTy) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check(_: impl std::marker::UnsizedConstParamTy) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 help: use parentheses to call this closure
    |
 LL |     check(|| {}());
@@ -38,15 +38,15 @@ error[E0277]: `fn()` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad.rs:9:11
    |
 LL |     check(main as fn());
-   |     ----- ^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `fn()`
+   |     ----- ^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `fn()`
    |     |
    |     required by a bound introduced by this call
    |
 note: required by a bound in `check`
   --> $DIR/const_param_ty_bad.rs:4:18
    |
-LL | fn check(_: impl std::marker::ConstParamTy) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check(_: impl std::marker::UnsizedConstParamTy) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 help: use parentheses to call this function pointer
    |
 LL |     check(main as fn()());
@@ -56,16 +56,16 @@ error[E0277]: `&mut ()` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad.rs:10:11
    |
 LL |     check(&mut ());
-   |     ----- ^^^^^^^ the trait `ConstParamTy` is not implemented for `&mut ()`
+   |     ----- ^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `&mut ()`
    |     |
    |     required by a bound introduced by this call
    |
-   = note: `ConstParamTy` is implemented for `&()`, but not for `&mut ()`
+   = note: `UnsizedConstParamTy` is implemented for `&()`, but not for `&mut ()`
 note: required by a bound in `check`
   --> $DIR/const_param_ty_bad.rs:4:18
    |
-LL | fn check(_: impl std::marker::ConstParamTy) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check(_: impl std::marker::UnsizedConstParamTy) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 help: consider removing the leading `&`-reference
    |
 LL -     check(&mut ());
@@ -76,31 +76,31 @@ error[E0277]: `*mut ()` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad.rs:11:11
    |
 LL |     check(&mut () as *mut ());
-   |     ----- ^^^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*mut ()`
+   |     ----- ^^^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*mut ()`
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `ConstParamTy` is implemented for `()`
+   = help: the trait `UnsizedConstParamTy` is implemented for `()`
 note: required by a bound in `check`
   --> $DIR/const_param_ty_bad.rs:4:18
    |
-LL | fn check(_: impl std::marker::ConstParamTy) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check(_: impl std::marker::UnsizedConstParamTy) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 
 error[E0277]: `*const ()` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad.rs:12:11
    |
 LL |     check(&() as *const ());
-   |     ----- ^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*const ()`
+   |     ----- ^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*const ()`
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `ConstParamTy` is implemented for `()`
+   = help: the trait `UnsizedConstParamTy` is implemented for `()`
 note: required by a bound in `check`
   --> $DIR/const_param_ty_bad.rs:4:18
    |
-LL | fn check(_: impl std::marker::ConstParamTy) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check(_: impl std::marker::UnsizedConstParamTy) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs
index b0e3b13cc1e..2008a96310a 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs
@@ -1,10 +1,10 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 #[derive(PartialEq, Eq)]
 struct NotParam;
 
-fn check<T: std::marker::ConstParamTy>() {}
+fn check<T: std::marker::ConstParamTy_>() {}
 
 fn main() {
     check::<[NotParam; 0]>();
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr
index 771d661f615..9852e181b9a 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr
@@ -2,14 +2,14 @@ error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad_empty_array.rs:10:13
    |
 LL |     check::<[NotParam; 0]>();
-   |             ^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy`
+   |             ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy_`
    |
-   = note: required for `[NotParam; 0]` to implement `ConstParamTy`
+   = note: required for `[NotParam; 0]` to implement `ConstParamTy_`
 note: required by a bound in `check`
   --> $DIR/const_param_ty_bad_empty_array.rs:7:13
    |
-LL | fn check<T: std::marker::ConstParamTy>() {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check<T: std::marker::ConstParamTy_>() {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs
index e4dc76703a2..7ffdafa33e9 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs
@@ -1,13 +1,13 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 #[derive(PartialEq, Eq)]
 struct NotParam;
 
-fn check<T: std::marker::ConstParamTy + ?Sized>() {}
+fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {}
 
 fn main() {
-    check::<&NotParam>();      //~ error: `NotParam` can't be used as a const parameter type
-    check::<[NotParam]>();     //~ error: `NotParam` can't be used as a const parameter type
+    check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type
+    check::<[NotParam]>(); //~ error: `NotParam` can't be used as a const parameter type
     check::<[NotParam; 17]>(); //~ error: `NotParam` can't be used as a const parameter type
 }
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr
index 83c34c41f10..e63ae582fd5 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr
@@ -2,40 +2,40 @@ error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13
    |
 LL |     check::<&NotParam>();
-   |             ^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: ConstParamTy`
+   |             ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: UnsizedConstParamTy`
    |
-   = note: required for `&NotParam` to implement `ConstParamTy`
+   = note: required for `&NotParam` to implement `UnsizedConstParamTy`
 note: required by a bound in `check`
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13
    |
-LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 
 error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13
    |
 LL |     check::<[NotParam]>();
-   |             ^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: ConstParamTy`
+   |             ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: UnsizedConstParamTy`
    |
-   = note: required for `[NotParam]` to implement `ConstParamTy`
+   = note: required for `[NotParam]` to implement `UnsizedConstParamTy`
 note: required by a bound in `check`
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13
    |
-LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 
 error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13
    |
 LL |     check::<[NotParam; 17]>();
-   |             ^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: ConstParamTy`
+   |             ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: UnsizedConstParamTy`
    |
-   = note: required for `[NotParam; 17]` to implement `ConstParamTy`
+   = note: required for `[NotParam; 17]` to implement `UnsizedConstParamTy`
 note: required by a bound in `check`
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13
    |
-LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs
index bce24059de8..98a8eb6ee95 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs
@@ -1,7 +1,9 @@
 //@ check-pass
+
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
-use std::marker::ConstParamTy;
+
+use std::marker::UnsizedConstParamTy;
 
 #[derive(PartialEq, Eq)]
 struct S<T> {
@@ -9,16 +11,15 @@ struct S<T> {
     gen: T,
 }
 
-impl<T: ConstParamTy> ConstParamTy for S<T> {}
+impl<T: UnsizedConstParamTy> UnsizedConstParamTy for S<T> {}
 
-#[derive(PartialEq, Eq, ConstParamTy)]
+#[derive(PartialEq, Eq, UnsizedConstParamTy)]
 struct D<T> {
     field: u8,
     gen: T,
 }
 
-
-fn check<T: ConstParamTy + ?Sized>() {}
+fn check<T: UnsizedConstParamTy + ?Sized>() {}
 
 fn main() {
     check::<u8>();
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs
index 74283a37afc..8b3d0546010 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs
@@ -1,5 +1,5 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 #[derive(PartialEq, Eq)]
 struct NotParam;
@@ -7,11 +7,11 @@ struct NotParam;
 #[derive(PartialEq, Eq)]
 struct CantParam(NotParam);
 
-impl std::marker::ConstParamTy for CantParam {}
-//~^ error: the trait `ConstParamTy` cannot be implemented for this type
+impl std::marker::UnsizedConstParamTy for CantParam {}
+//~^ error: the trait `ConstParamTy_` cannot be implemented for this type
 
-#[derive(std::marker::ConstParamTy, Eq, PartialEq)]
-//~^ error: the trait `ConstParamTy` cannot be implemented for this type
+#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)]
+//~^ error: the trait `ConstParamTy_` cannot be implemented for this type
 struct CantParamDerive(NotParam);
 
 fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr
index 52b65d6061a..808a569fcad 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr
@@ -1,22 +1,22 @@
-error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
-  --> $DIR/const_param_ty_impl_bad_field.rs:10:36
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/const_param_ty_impl_bad_field.rs:10:43
    |
 LL | struct CantParam(NotParam);
-   |                  -------- this field does not implement `ConstParamTy`
+   |                  -------- this field does not implement `ConstParamTy_`
 LL |
-LL | impl std::marker::ConstParamTy for CantParam {}
-   |                                    ^^^^^^^^^
+LL | impl std::marker::UnsizedConstParamTy for CantParam {}
+   |                                           ^^^^^^^^^
 
-error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
   --> $DIR/const_param_ty_impl_bad_field.rs:13:10
    |
-LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL | struct CantParamDerive(NotParam);
-   |                        -------- this field does not implement `ConstParamTy`
+   |                        -------- this field does not implement `ConstParamTy_`
    |
-   = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs
index dfb8a36ec53..761a6387a24 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs
@@ -1,22 +1,22 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 #[derive(PartialEq, Eq)]
 struct ImplementsConstParamTy;
-impl std::marker::ConstParamTy for ImplementsConstParamTy {}
+impl std::marker::UnsizedConstParamTy for ImplementsConstParamTy {}
 
 struct CantParam(ImplementsConstParamTy);
 
-impl std::marker::ConstParamTy for CantParam {}
+impl std::marker::UnsizedConstParamTy for CantParam {}
 //~^ error: the type `CantParam` does not `#[derive(PartialEq)]`
 //~| the trait bound `CantParam: Eq` is not satisfied
 
-#[derive(std::marker::ConstParamTy)]
+#[derive(std::marker::UnsizedConstParamTy)]
 //~^ error: the type `CantParamDerive` does not `#[derive(PartialEq)]`
 //~| the trait bound `CantParamDerive: Eq` is not satisfied
 struct CantParamDerive(ImplementsConstParamTy);
 
-fn check<T: std::marker::ConstParamTy>() {}
+fn check<T: std::marker::UnsizedConstParamTy>() {}
 
 fn main() {
     check::<ImplementsConstParamTy>();
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr
index e213808cf7b..80d9942c591 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr
@@ -1,10 +1,10 @@
 error[E0277]: the trait bound `CantParam: Eq` is not satisfied
-  --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36
+  --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43
    |
-LL | impl std::marker::ConstParamTy for CantParam {}
-   |                                    ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam`
+LL | impl std::marker::UnsizedConstParamTy for CantParam {}
+   |                                           ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam`
    |
-note: required by a bound in `ConstParamTy`
+note: required by a bound in `UnsizedConstParamTy`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
 help: consider annotating `CantParam` with `#[derive(Eq)]`
    |
@@ -13,23 +13,23 @@ LL | struct CantParam(ImplementsConstParamTy);
    |
 
 error[E0277]: the type `CantParam` does not `#[derive(PartialEq)]`
-  --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36
+  --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43
    |
-LL | impl std::marker::ConstParamTy for CantParam {}
-   |                                    ^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParam`
+LL | impl std::marker::UnsizedConstParamTy for CantParam {}
+   |                                           ^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParam`
    |
-note: required by a bound in `ConstParamTy`
+note: required by a bound in `UnsizedConstParamTy`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
 
 error[E0277]: the trait bound `CantParamDerive: Eq` is not satisfied
   --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10
    |
-LL | #[derive(std::marker::ConstParamTy)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive`
+LL | #[derive(std::marker::UnsizedConstParamTy)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive`
    |
-note: required by a bound in `ConstParamTy`
+note: required by a bound in `UnsizedConstParamTy`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
-   = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `CantParamDerive` with `#[derive(Eq)]`
    |
 LL + #[derive(Eq)]
@@ -39,12 +39,12 @@ LL | struct CantParamDerive(ImplementsConstParamTy);
 error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]`
   --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10
    |
-LL | #[derive(std::marker::ConstParamTy)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive`
+LL | #[derive(std::marker::UnsizedConstParamTy)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive`
    |
-note: required by a bound in `ConstParamTy`
+note: required by a bound in `UnsizedConstParamTy`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
-   = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs
index f2986f9cc60..236b3bc162a 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs
@@ -1,5 +1,5 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 union Union {
     a: u8,
@@ -12,10 +12,10 @@ impl PartialEq for Union {
 }
 impl Eq for Union {}
 
-impl std::marker::ConstParamTy for Union {}
-//~^ ERROR the type `Union` does not `#[derive(PartialEq)]`
+impl std::marker::UnsizedConstParamTy for Union {}
+//~^ ERROR the trait `ConstParamTy` may not be implemented for this type
 
-#[derive(std::marker::ConstParamTy)]
+#[derive(std::marker::UnsizedConstParamTy)]
 //~^ ERROR this trait cannot be derived for unions
 union UnionDerive {
     a: u8,
@@ -28,5 +28,4 @@ impl PartialEq for UnionDerive {
 }
 impl Eq for UnionDerive {}
 
-
 fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr
index 4c937db6c3a..837c289c924 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr
@@ -1,18 +1,14 @@
 error: this trait cannot be derived for unions
   --> $DIR/const_param_ty_impl_union.rs:18:10
    |
-LL | #[derive(std::marker::ConstParamTy)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[derive(std::marker::UnsizedConstParamTy)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: the type `Union` does not `#[derive(PartialEq)]`
-  --> $DIR/const_param_ty_impl_union.rs:15:36
+error: the trait `ConstParamTy` may not be implemented for this type
+  --> $DIR/const_param_ty_impl_union.rs:15:43
    |
-LL | impl std::marker::ConstParamTy for Union {}
-   |                                    ^^^^^ the trait `StructuralPartialEq` is not implemented for `Union`
-   |
-note: required by a bound in `ConstParamTy`
-  --> $SRC_DIR/core/src/marker.rs:LL:COL
+LL | impl std::marker::UnsizedConstParamTy for Union {}
+   |                                           ^^^^^ type is not a structure or enumeration
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs
new file mode 100644
index 00000000000..6a553c2e085
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs
@@ -0,0 +1,12 @@
+#![feature(adt_const_params, unsized_const_params)]
+#![allow(incomplete_features)]
+
+use std::marker::{ConstParamTy_, UnsizedConstParamTy};
+
+fn foo(a: &dyn ConstParamTy_) {}
+//~^ ERROR: the trait `ConstParamTy_`
+
+fn bar(a: &dyn UnsizedConstParamTy) {}
+//~^ ERROR: the trait `UnsizedConstParamTy`
+
+fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr
new file mode 100644
index 00000000000..ba38f63d5df
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr
@@ -0,0 +1,33 @@
+error[E0038]: the trait `ConstParamTy_` cannot be made into an object
+  --> $DIR/const_param_ty_object_safety.rs:6:12
+   |
+LL | fn foo(a: &dyn ConstParamTy_) {}
+   |            ^^^^^^^^^^^^^^^^^ `ConstParamTy_` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: the trait cannot be made into an object because it uses `Self` as a type parameter
+help: consider using an opaque type instead
+   |
+LL | fn foo(a: &impl ConstParamTy_) {}
+   |            ~~~~
+
+error[E0038]: the trait `UnsizedConstParamTy` cannot be made into an object
+  --> $DIR/const_param_ty_object_safety.rs:9:12
+   |
+LL | fn bar(a: &dyn UnsizedConstParamTy) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: the trait cannot be made into an object because it uses `Self` as a type parameter
+help: consider using an opaque type instead
+   |
+LL | fn bar(a: &impl UnsizedConstParamTy) {}
+   |            ~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs
index 0d1f023d565..7a4970c2e3c 100644
--- a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs
+++ b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs
@@ -1,18 +1,30 @@
 // issue: rust-lang/rust/#83993
 
 #![feature(adt_const_params)]
-//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+
 fn bug<'a>()
 where
     for<'b> [(); {
         let x: &'b ();
         //~^ ERROR generic parameters may not be used in const operations
         0
-    }]:
-{}
+    }]:,
+{
+}
 
-fn bad() where for<'b> [();{let _:&'b (); 0}]: Sized { }
-//~^ ERROR generic parameters may not be used in const operations
-fn good() where for<'b> [();{0}]: Sized { }
+fn bad()
+where
+    for<'b> [(); {
+        let _: &'b ();
+        //~^ ERROR generic parameters may not be used in const operations
+        0
+    }]: Sized,
+{
+}
+fn good()
+where
+    for<'b> [(); { 0 }]: Sized,
+{
+}
 
 pub fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr
index a49dfc31916..b7e459511f1 100644
--- a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr
+++ b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr
@@ -8,22 +8,13 @@ LL |         let x: &'b ();
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/index-oob-ice-83993.rs:14:36
+  --> $DIR/index-oob-ice-83993.rs:18:17
    |
-LL | fn bad() where for<'b> [();{let _:&'b (); 0}]: Sized { }
-   |                                    ^^ cannot perform const operation using `'b`
+LL |         let _: &'b ();
+   |                 ^^ cannot perform const operation using `'b`
    |
    = note: lifetime parameters may not be used in const expressions
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/index-oob-ice-83993.rs:3:12
-   |
-LL | #![feature(adt_const_params)]
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs
index 9f05c53eef0..3a283442a0b 100644
--- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs
+++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs
@@ -4,15 +4,18 @@
 use std::marker::ConstParamTy;
 
 #[derive(ConstParamTy)]
-//~^ the trait `ConstParamTy` cannot be implemented for this ty
+//~^ the trait `ConstParamTy_` cannot be implemented for this ty
+//~| the trait `ConstParamTy_` cannot be implemented for this ty
 struct Foo([*const u8; 1]);
 
 #[derive(ConstParamTy)]
-//~^ the trait `ConstParamTy` cannot be implemented for this ty
+//~^ the trait `ConstParamTy_` cannot be implemented for this ty
+//~| the trait `ConstParamTy_` cannot be implemented for this ty
 struct Foo2([*mut u8; 1]);
 
 #[derive(ConstParamTy)]
-//~^ the trait `ConstParamTy` cannot be implemented for this ty
+//~^ the trait `ConstParamTy_` cannot be implemented for this ty
+//~| the trait `ConstParamTy_` cannot be implemented for this ty
 struct Foo3([fn(); 1]);
 
 fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr
index 9e772e8d55d..c2520f1d103 100644
--- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr
+++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr
@@ -1,51 +1,99 @@
-error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
   --> $DIR/nested_bad_const_param_ty.rs:6:10
    |
 LL | #[derive(ConstParamTy)]
    |          ^^^^^^^^^^^^
-LL |
+...
 LL | struct Foo([*const u8; 1]);
-   |            -------------- this field does not implement `ConstParamTy`
+   |            -------------- this field does not implement `ConstParamTy_`
    |
-note: the `ConstParamTy` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy`
-  --> $DIR/nested_bad_const_param_ty.rs:8:12
+note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy_`
+  --> $DIR/nested_bad_const_param_ty.rs:9:12
    |
 LL | struct Foo([*const u8; 1]);
    |            ^^^^^^^^^^^^^^
    = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
-  --> $DIR/nested_bad_const_param_ty.rs:10:10
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:11:10
    |
 LL | #[derive(ConstParamTy)]
    |          ^^^^^^^^^^^^
-LL |
+...
 LL | struct Foo2([*mut u8; 1]);
-   |             ------------ this field does not implement `ConstParamTy`
+   |             ------------ this field does not implement `ConstParamTy_`
    |
-note: the `ConstParamTy` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy`
-  --> $DIR/nested_bad_const_param_ty.rs:12:13
+note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy_`
+  --> $DIR/nested_bad_const_param_ty.rs:14:13
    |
 LL | struct Foo2([*mut u8; 1]);
    |             ^^^^^^^^^^^^
    = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
-  --> $DIR/nested_bad_const_param_ty.rs:14:10
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:16:10
    |
 LL | #[derive(ConstParamTy)]
    |          ^^^^^^^^^^^^
-LL |
+...
 LL | struct Foo3([fn(); 1]);
-   |             --------- this field does not implement `ConstParamTy`
+   |             --------- this field does not implement `ConstParamTy_`
    |
-note: the `ConstParamTy` impl for `[fn(); 1]` requires that `fn(): ConstParamTy`
-  --> $DIR/nested_bad_const_param_ty.rs:16:13
+note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): ConstParamTy_`
+  --> $DIR/nested_bad_const_param_ty.rs:19:13
    |
 LL | struct Foo3([fn(); 1]);
    |             ^^^^^^^^^
    = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:6:10
+   |
+LL | #[derive(ConstParamTy)]
+   |          ^^^^^^^^^^^^
+...
+LL | struct Foo([*const u8; 1]);
+   |            -------------- this field does not implement `ConstParamTy_`
+   |
+note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: UnsizedConstParamTy`
+  --> $DIR/nested_bad_const_param_ty.rs:9:12
+   |
+LL | struct Foo([*const u8; 1]);
+   |            ^^^^^^^^^^^^^^
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:11:10
+   |
+LL | #[derive(ConstParamTy)]
+   |          ^^^^^^^^^^^^
+...
+LL | struct Foo2([*mut u8; 1]);
+   |             ------------ this field does not implement `ConstParamTy_`
+   |
+note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: UnsizedConstParamTy`
+  --> $DIR/nested_bad_const_param_ty.rs:14:13
+   |
+LL | struct Foo2([*mut u8; 1]);
+   |             ^^^^^^^^^^^^
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:16:10
+   |
+LL | #[derive(ConstParamTy)]
+   |          ^^^^^^^^^^^^
+...
+LL | struct Foo3([fn(); 1]);
+   |             --------- this field does not implement `ConstParamTy_`
+   |
+note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): UnsizedConstParamTy`
+  --> $DIR/nested_bad_const_param_ty.rs:19:13
+   |
+LL | struct Foo3([fn(); 1]);
+   |             ^^^^^^^^^
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0204`.
diff --git a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs
index c55f3dcec68..f28bebf85db 100644
--- a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs
+++ b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs
@@ -3,7 +3,7 @@
 // issues rust-lang/rust#111911
 // test for ICE opaque type with non-universal region substs
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 pub async fn foo<const X: &'static str>() {}
diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs
new file mode 100644
index 00000000000..a1ee1c4cdd5
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs
@@ -0,0 +1,11 @@
+#![feature(adt_const_params, unsized_const_params)]
+#![allow(incomplete_features)]
+
+use std::marker::UnsizedConstParamTy;
+
+struct Foo;
+
+impl UnsizedConstParamTy for &'static Foo {}
+//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type
+
+fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr
new file mode 100644
index 00000000000..5ca8e6c7516
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr
@@ -0,0 +1,9 @@
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/reference_pointee_is_const_param-1.rs:8:30
+   |
+LL | impl UnsizedConstParamTy for &'static Foo {}
+   |                              ^^^^^^^^^^^^ this field does not implement `ConstParamTy_`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs
new file mode 100644
index 00000000000..ac1b522f469
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs
@@ -0,0 +1,27 @@
+#![feature(adt_const_params, unsized_const_params)]
+#![allow(incomplete_features)]
+
+// Regression test for #119299
+
+use std::marker::UnsizedConstParamTy;
+
+#[derive(Eq, PartialEq)]
+struct ConstStrU(*const u8, usize);
+
+impl UnsizedConstParamTy for &'static ConstStrU {}
+//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type
+
+impl ConstStrU {
+    const fn from_bytes(bytes: &'static [u8]) -> Self {
+        Self(bytes.as_ptr(), bytes.len())
+    }
+}
+
+const fn chars_s<const S: &'static ConstStrU>() -> [char; 3] {
+    ['a', 'b', 'c']
+}
+
+fn main() {
+    const A: &'static ConstStrU = &ConstStrU::from_bytes(b"abc");
+    chars_s::<A>();
+}
diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr
new file mode 100644
index 00000000000..5e5f6cc642d
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr
@@ -0,0 +1,9 @@
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/reference_pointee_is_const_param-2.rs:11:30
+   |
+LL | impl UnsizedConstParamTy for &'static ConstStrU {}
+   |                              ^^^^^^^^^^^^^^^^^^ this field does not implement `ConstParamTy_`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs
index 0d2e65c45ea..33988bc0678 100644
--- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs
+++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs
@@ -8,9 +8,8 @@ fn uwu_0<const N: &'static mut ()>() {}
 //~| HELP: add `#![feature(adt_const_params)]`
 //~| HELP: add `#![feature(adt_const_params)]`
 //~| HELP: add `#![feature(adt_const_params)]`
-//~| HELP: add `#![feature(adt_const_params)]`
-//~| HELP: add `#![feature(adt_const_params)]`
-//~| HELP: add `#![feature(adt_const_params)]`
+//~| HELP: add `#![feature(unsized_const_params)]`
+//~| HELP: add `#![feature(unsized_const_params)]`
 
 // Needs the feature but can be used, so suggest adding the feature.
 fn owo_0<const N: &'static u32>() {}
diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
index cd4349623d7..aafc0640dd2 100644
--- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
+++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
@@ -7,7 +7,7 @@ LL | fn uwu_0<const N: &'static mut ()>() {}
    = note: the only supported types are integers, `bool` and `char`
 
 error: `&'static u32` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:16:19
+  --> $DIR/suggest_feature_only_when_possible.rs:15:19
    |
 LL | fn owo_0<const N: &'static u32>() {}
    |                   ^^^^^^^^^^^^
@@ -17,9 +17,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `Meow` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:24:20
+  --> $DIR/suggest_feature_only_when_possible.rs:23:20
    |
 LL | fn meow_0<const N: Meow>() {}
    |                    ^^^^
@@ -31,7 +35,7 @@ LL + #![feature(adt_const_params)]
    |
 
 error: `&'static Meow` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:26:20
+  --> $DIR/suggest_feature_only_when_possible.rs:25:20
    |
 LL | fn meow_1<const N: &'static Meow>() {}
    |                    ^^^^^^^^^^^^^
@@ -41,45 +45,37 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `[Meow; 100]` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:28:20
+  --> $DIR/suggest_feature_only_when_possible.rs:27:20
    |
 LL | fn meow_2<const N: [Meow; 100]>() {}
    |                    ^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
 
 error: `(Meow, u8)` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:30:20
+  --> $DIR/suggest_feature_only_when_possible.rs:29:20
    |
 LL | fn meow_3<const N: (Meow, u8)>() {}
    |                    ^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
 
 error: `(Meow, String)` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:35:20
+  --> $DIR/suggest_feature_only_when_possible.rs:34:20
    |
 LL | fn meow_4<const N: (Meow, String)>() {}
    |                    ^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
 
 error: `String` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:39:19
+  --> $DIR/suggest_feature_only_when_possible.rs:38:19
    |
 LL | fn nya_0<const N: String>() {}
    |                   ^^^^^^
@@ -87,7 +83,7 @@ LL | fn nya_0<const N: String>() {}
    = note: the only supported types are integers, `bool` and `char`
 
 error: `Vec<u32>` is forbidden as the type of a const generic parameter
-  --> $DIR/suggest_feature_only_when_possible.rs:41:19
+  --> $DIR/suggest_feature_only_when_possible.rs:40:19
    |
 LL | fn nya_1<const N: Vec<u32>>() {}
    |                   ^^^^^^^^
diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs
new file mode 100644
index 00000000000..b0934508399
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs
@@ -0,0 +1,13 @@
+#![feature(adt_const_params, unsized_const_params)]
+#![allow(incomplete_features)]
+
+use std::marker::UnsizedConstParamTy;
+
+trait Trait {}
+
+impl UnsizedConstParamTy for dyn Trait {}
+//~^ ERROR: the trait `ConstParamTy` may not be implemented for this type
+
+fn foo<const N: dyn Trait>() {}
+
+fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr
new file mode 100644
index 00000000000..9933ba6e335
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr
@@ -0,0 +1,8 @@
+error: the trait `ConstParamTy` may not be implemented for this type
+  --> $DIR/trait_objects_as_a_const_generic.rs:8:30
+   |
+LL | impl UnsizedConstParamTy for dyn Trait {}
+   |                              ^^^^^^^^^ type is not a structure or enumeration
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.rs b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs
new file mode 100644
index 00000000000..f6e5bd6e355
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs
@@ -0,0 +1,20 @@
+//@ aux-build:unsized_const_param.rs
+#![feature(adt_const_params)]
+
+extern crate unsized_const_param;
+
+use std::marker::ConstParamTy;
+
+#[derive(ConstParamTy, Eq, PartialEq)]
+//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type
+struct A([u8]);
+
+#[derive(ConstParamTy, Eq, PartialEq)]
+//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type
+struct B(&'static [u8]);
+
+#[derive(ConstParamTy, Eq, PartialEq)]
+//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type
+struct C(unsized_const_param::Foo);
+
+fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr
new file mode 100644
index 00000000000..7a4f9b99c63
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr
@@ -0,0 +1,36 @@
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/unsized_field-1.rs:8:10
+   |
+LL | #[derive(ConstParamTy, Eq, PartialEq)]
+   |          ^^^^^^^^^^^^
+LL |
+LL | struct A([u8]);
+   |          ---- this field does not implement `ConstParamTy_`
+   |
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/unsized_field-1.rs:12:10
+   |
+LL | #[derive(ConstParamTy, Eq, PartialEq)]
+   |          ^^^^^^^^^^^^
+LL |
+LL | struct B(&'static [u8]);
+   |          ------------- this field does not implement `ConstParamTy_`
+   |
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/unsized_field-1.rs:16:10
+   |
+LL | #[derive(ConstParamTy, Eq, PartialEq)]
+   |          ^^^^^^^^^^^^
+LL |
+LL | struct C(unsized_const_param::Foo);
+   |          ------------------------ this field does not implement `ConstParamTy_`
+   |
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.rs b/tests/ui/const-generics/adt_const_params/unsized_field-2.rs
new file mode 100644
index 00000000000..e4a3a481b4e
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/unsized_field-2.rs
@@ -0,0 +1,14 @@
+//@ aux-build:unsized_const_param.rs
+#![feature(adt_const_params, unsized_const_params)]
+//~^ WARN: the feature `unsized_const_params` is incomplete
+
+extern crate unsized_const_param;
+
+#[derive(std::marker::ConstParamTy, Eq, PartialEq)]
+//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type
+struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>);
+
+#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)]
+struct B(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>);
+
+fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr
new file mode 100644
index 00000000000..15acece538f
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr
@@ -0,0 +1,28 @@
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/unsized_field-2.rs:2:30
+   |
+LL | #![feature(adt_const_params, unsized_const_params)]
+   |                              ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/unsized_field-2.rs:7:10
+   |
+LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>);
+   |          ---------------------------------------------------------- this field does not implement `ConstParamTy_`
+   |
+note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `&'static [u8]: ConstParamTy_`
+  --> $DIR/unsized_field-2.rs:9:10
+   |
+LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>);
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
index 1c81b14f8f5..62267224738 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
+++ b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
@@ -39,6 +39,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:14:15
@@ -51,6 +55,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:22:15
@@ -63,6 +71,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:26:17
@@ -75,6 +87,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:17:21
@@ -87,6 +103,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.rs b/tests/ui/const-generics/const-param-elided-lifetime.rs
index ef1eecb59be..e75073de98d 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.rs
+++ b/tests/ui/const-generics/const-param-elided-lifetime.rs
@@ -3,7 +3,7 @@
 // elided lifetimes within the type of a const generic parameters to be 'static, like elided
 // lifetimes within const/static items.
 //@ revisions: full min
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
 
 struct A<const N: &u8>;
@@ -12,8 +12,8 @@ struct A<const N: &u8>;
 trait B {}
 
 impl<const N: &u8> A<N> {
-//~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&u8` is forbidden
+    //~^ ERROR `&` without an explicit lifetime name cannot be used here
+    //[min]~^^ ERROR `&u8` is forbidden
     fn foo<const M: &u8>(&self) {}
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
     //[min]~^^ ERROR `&u8` is forbidden
diff --git a/tests/ui/const-generics/const-param-with-additional-obligations.rs b/tests/ui/const-generics/const-param-with-additional-obligations.rs
index f53cf85cdd3..98097e86c7d 100644
--- a/tests/ui/const-generics/const-param-with-additional-obligations.rs
+++ b/tests/ui/const-generics/const-param-with-additional-obligations.rs
@@ -1,14 +1,14 @@
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
-use std::marker::ConstParamTy;
+use std::marker::UnsizedConstParamTy;
 
 #[derive(Eq, PartialEq)]
 struct Foo<T>(T);
 
 trait Other {}
 
-impl<T> ConstParamTy for Foo<T> where T: Other + ConstParamTy {}
+impl<T> UnsizedConstParamTy for Foo<T> where T: Other + UnsizedConstParamTy {}
 
 fn foo<const N: Foo<u8>>() {}
 //~^ ERROR `Foo<u8>` must implement `ConstParamTy` to be used as the type of a const generic parameter
diff --git a/tests/ui/const-generics/float-generic.adt_const_params.stderr b/tests/ui/const-generics/float-generic.adt_const_params.stderr
index cae4806368a..1a7c19ba4be 100644
--- a/tests/ui/const-generics/float-generic.adt_const_params.stderr
+++ b/tests/ui/const-generics/float-generic.adt_const_params.stderr
@@ -1,5 +1,5 @@
 error[E0741]: `f32` is forbidden as the type of a const generic parameter
-  --> $DIR/float-generic.rs:5:17
+  --> $DIR/float-generic.rs:7:17
    |
 LL | fn foo<const F: f32>() {}
    |                 ^^^
diff --git a/tests/ui/const-generics/float-generic.full.stderr b/tests/ui/const-generics/float-generic.full.stderr
new file mode 100644
index 00000000000..1a7c19ba4be
--- /dev/null
+++ b/tests/ui/const-generics/float-generic.full.stderr
@@ -0,0 +1,9 @@
+error[E0741]: `f32` is forbidden as the type of a const generic parameter
+  --> $DIR/float-generic.rs:7:17
+   |
+LL | fn foo<const F: f32>() {}
+   |                 ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/tests/ui/const-generics/float-generic.rs b/tests/ui/const-generics/float-generic.rs
index aaf63a93d70..f92e1667701 100644
--- a/tests/ui/const-generics/float-generic.rs
+++ b/tests/ui/const-generics/float-generic.rs
@@ -1,4 +1,6 @@
-//@ revisions: simple adt_const_params
+//@ revisions: simple adt_const_params full
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
+#![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(adt_const_params, feature(adt_const_params))]
 #![cfg_attr(adt_const_params, allow(incomplete_features))]
 
diff --git a/tests/ui/const-generics/float-generic.simple.stderr b/tests/ui/const-generics/float-generic.simple.stderr
index eccf9059ee3..2999bce32d6 100644
--- a/tests/ui/const-generics/float-generic.simple.stderr
+++ b/tests/ui/const-generics/float-generic.simple.stderr
@@ -1,5 +1,5 @@
 error: `f32` is forbidden as the type of a const generic parameter
-  --> $DIR/float-generic.rs:5:17
+  --> $DIR/float-generic.rs:7:17
    |
 LL | fn foo<const F: f32>() {}
    |                 ^^^
diff --git a/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr b/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr
new file mode 100644
index 00000000000..fd9346a533e
--- /dev/null
+++ b/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr
@@ -0,0 +1,15 @@
+error[E0741]: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:13:25
+   |
+LL | struct Wrapper<const F: fn() -> u32>;
+   |                         ^^^^^^^^^^^
+
+error[E0741]: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:15:15
+   |
+LL | impl<const F: fn() -> u32> Wrapper<F> {
+   |               ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/tests/ui/const-generics/fn-const-param-call.full.stderr b/tests/ui/const-generics/fn-const-param-call.full.stderr
index b55c2449858..fd9346a533e 100644
--- a/tests/ui/const-generics/fn-const-param-call.full.stderr
+++ b/tests/ui/const-generics/fn-const-param-call.full.stderr
@@ -1,11 +1,11 @@
 error[E0741]: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:11:25
+  --> $DIR/fn-const-param-call.rs:13:25
    |
 LL | struct Wrapper<const F: fn() -> u32>;
    |                         ^^^^^^^^^^^
 
 error[E0741]: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:13:15
+  --> $DIR/fn-const-param-call.rs:15:15
    |
 LL | impl<const F: fn() -> u32> Wrapper<F> {
    |               ^^^^^^^^^^^
diff --git a/tests/ui/const-generics/fn-const-param-call.min.stderr b/tests/ui/const-generics/fn-const-param-call.min.stderr
index 2d316fba1e9..d37766b28c9 100644
--- a/tests/ui/const-generics/fn-const-param-call.min.stderr
+++ b/tests/ui/const-generics/fn-const-param-call.min.stderr
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:11:25
+  --> $DIR/fn-const-param-call.rs:13:25
    |
 LL | struct Wrapper<const F: fn() -> u32>;
    |                         ^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | struct Wrapper<const F: fn() -> u32>;
    = note: the only supported types are integers, `bool` and `char`
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:13:15
+  --> $DIR/fn-const-param-call.rs:15:15
    |
 LL | impl<const F: fn() -> u32> Wrapper<F> {
    |               ^^^^^^^^^^^
diff --git a/tests/ui/const-generics/fn-const-param-call.rs b/tests/ui/const-generics/fn-const-param-call.rs
index ce780143178..d536c240239 100644
--- a/tests/ui/const-generics/fn-const-param-call.rs
+++ b/tests/ui/const-generics/fn-const-param-call.rs
@@ -1,8 +1,10 @@
 // Check that functions cannot be used as const parameters.
-//@ revisions: full min
+//@ revisions: min adt_const_params full
 
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(adt_const_params, feature(adt_const_params))]
+#![cfg_attr(adt_const_params, allow(incomplete_features))]
 
 fn function() -> u32 {
     17
@@ -11,7 +13,7 @@ fn function() -> u32 {
 struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters
 
 impl<const F: fn() -> u32> Wrapper<F> {
-//~^ ERROR: using function pointers as const generic parameters
+    //~^ ERROR: using function pointers as const generic parameters
     fn call() -> u32 {
         F()
     }
diff --git a/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr b/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr
new file mode 100644
index 00000000000..54f3bff172a
--- /dev/null
+++ b/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr
@@ -0,0 +1,30 @@
+error[E0741]: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-infer.rs:8:25
+   |
+LL | struct Checked<const F: fn(usize) -> bool>;
+   |                         ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/fn-const-param-infer.rs:33:25
+   |
+LL |     let _ = Checked::<{ generic_arg::<u32> }>;
+   |                         ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
+   |
+   = note: expected fn pointer `fn(usize) -> _`
+                 found fn item `fn(u32) -> _ {generic_arg::<u32>}`
+
+error[E0282]: type annotations needed
+  --> $DIR/fn-const-param-infer.rs:35:23
+   |
+LL |     let _ = Checked::<generic>;
+   |                       ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic`
+   |
+help: consider specifying the generic argument
+   |
+LL |     let _ = Checked::<generic::<T>>;
+   |                              +++++
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0282, E0308, E0741.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/const-generics/fn-const-param-infer.full.stderr b/tests/ui/const-generics/fn-const-param-infer.full.stderr
index 753558636e1..54f3bff172a 100644
--- a/tests/ui/const-generics/fn-const-param-infer.full.stderr
+++ b/tests/ui/const-generics/fn-const-param-infer.full.stderr
@@ -1,20 +1,20 @@
 error[E0741]: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-infer.rs:6:25
+  --> $DIR/fn-const-param-infer.rs:8:25
    |
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:23:24
+  --> $DIR/fn-const-param-infer.rs:33:25
    |
-LL |     let _ = Checked::<{generic_arg::<u32>}>;
-   |                        ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
+LL |     let _ = Checked::<{ generic_arg::<u32> }>;
+   |                         ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
    |
    = note: expected fn pointer `fn(usize) -> _`
                  found fn item `fn(u32) -> _ {generic_arg::<u32>}`
 
 error[E0282]: type annotations needed
-  --> $DIR/fn-const-param-infer.rs:25:23
+  --> $DIR/fn-const-param-infer.rs:35:23
    |
 LL |     let _ = Checked::<generic>;
    |                       ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic`
diff --git a/tests/ui/const-generics/fn-const-param-infer.min.stderr b/tests/ui/const-generics/fn-const-param-infer.min.stderr
index 01e224f8d9c..4da503d344a 100644
--- a/tests/ui/const-generics/fn-const-param-infer.min.stderr
+++ b/tests/ui/const-generics/fn-const-param-infer.min.stderr
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-infer.rs:6:25
+  --> $DIR/fn-const-param-infer.rs:8:25
    |
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
@@ -7,16 +7,16 @@ LL | struct Checked<const F: fn(usize) -> bool>;
    = note: the only supported types are integers, `bool` and `char`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:23:24
+  --> $DIR/fn-const-param-infer.rs:33:25
    |
-LL |     let _ = Checked::<{generic_arg::<u32>}>;
-   |                        ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
+LL |     let _ = Checked::<{ generic_arg::<u32> }>;
+   |                         ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
    |
    = note: expected fn pointer `fn(usize) -> _`
                  found fn item `fn(u32) -> _ {generic_arg::<u32>}`
 
 error[E0282]: type annotations needed
-  --> $DIR/fn-const-param-infer.rs:25:23
+  --> $DIR/fn-const-param-infer.rs:35:23
    |
 LL |     let _ = Checked::<generic>;
    |                       ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic`
diff --git a/tests/ui/const-generics/fn-const-param-infer.rs b/tests/ui/const-generics/fn-const-param-infer.rs
index ed0bb9f7217..5f1958df26e 100644
--- a/tests/ui/const-generics/fn-const-param-infer.rs
+++ b/tests/ui/const-generics/fn-const-param-infer.rs
@@ -1,17 +1,27 @@
-//@ revisions: full min
+//@ revisions: min adt_const_params full
 
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(adt_const_params, feature(adt_const_params))]
+#![cfg_attr(adt_const_params, allow(incomplete_features))]
 
 struct Checked<const F: fn(usize) -> bool>;
 //~^ ERROR: using function pointers as const generic parameters
 
-fn not_one(val: usize) -> bool { val != 1 }
-fn not_two(val: usize) -> bool { val != 2 }
+fn not_one(val: usize) -> bool {
+    val != 1
+}
+fn not_two(val: usize) -> bool {
+    val != 2
+}
 
-fn generic_arg<T>(val: T) -> bool { true }
+fn generic_arg<T>(val: T) -> bool {
+    true
+}
 
-fn generic<T>(val: usize) -> bool { val != 1 }
+fn generic<T>(val: usize) -> bool {
+    val != 1
+}
 
 fn main() {
     let _: Option<Checked<not_one>> = None;
@@ -19,11 +29,11 @@ fn main() {
     let _: Checked<not_one> = Checked::<not_two>;
 
     let _ = Checked::<generic_arg>;
-    let _ = Checked::<{generic_arg::<usize>}>;
-    let _ = Checked::<{generic_arg::<u32>}>; //~ ERROR: mismatched types
+    let _ = Checked::<{ generic_arg::<usize> }>;
+    let _ = Checked::<{ generic_arg::<u32> }>; //~ ERROR: mismatched types
 
     let _ = Checked::<generic>; //~ ERROR: type annotations needed
-    let _ = Checked::<{generic::<u16>}>;
-    let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
-    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
+    let _ = Checked::<{ generic::<u16> }>;
+    let _: Checked<{ generic::<u16> }> = Checked::<{ generic::<u16> }>;
+    let _: Checked<{ generic::<u32> }> = Checked::<{ generic::<u16> }>;
 }
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-100360.rs b/tests/ui/const-generics/generic_const_exprs/issue-100360.rs
index b7e677a4a1e..37f015d5e0f 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-100360.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-100360.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 // (this requires debug assertions)
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 fn foo<const B: &'static bool>(arg: &'static bool) -> bool {
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-89851.rs b/tests/ui/const-generics/generic_const_exprs/issue-89851.rs
index 78189c5225c..f93ba30856d 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-89851.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-89851.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 // (this requires debug assertions)
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 pub const BAR: () = ice::<"">();
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs
index 5a6565fe2f1..443d0a2fe87 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
-#![feature(adt_const_params, generic_const_exprs)]
-//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
+//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
 //~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
 
 pub struct Changes<const CHANGES: &'static [&'static str]>
@@ -16,9 +16,7 @@ where
     [(); CHANGES.len()]:,
 {
     pub const fn new() -> Self {
-        Self {
-            changes: [0; CHANGES.len()],
-        }
+        Self { changes: [0; CHANGES.len()] }
     }
 }
 
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr
index 1cceaece715..b6b297593a2 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr
@@ -1,17 +1,17 @@
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-97047-ice-1.rs:3:12
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-97047-ice-1.rs:3:30
    |
-LL | #![feature(adt_const_params, generic_const_exprs)]
-   |            ^^^^^^^^^^^^^^^^
+LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
+   |                              ^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-97047-ice-1.rs:3:30
+  --> $DIR/issue-97047-ice-1.rs:3:52
    |
-LL | #![feature(adt_const_params, generic_const_exprs)]
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
+   |                                                    ^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
 
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs
index 1338f40208c..6a91b522567 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
-#![feature(adt_const_params, generic_const_exprs)]
-//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
+//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
 //~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
 
 pub struct Changes<const CHANGES: &'static [&'static str]>
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr
index 774e842bcbe..c0c7dcc79dc 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr
@@ -1,17 +1,17 @@
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-97047-ice-2.rs:3:12
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-97047-ice-2.rs:3:30
    |
-LL | #![feature(adt_const_params, generic_const_exprs)]
-   |            ^^^^^^^^^^^^^^^^
+LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
+   |                              ^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-97047-ice-2.rs:3:30
+  --> $DIR/issue-97047-ice-2.rs:3:52
    |
-LL | #![feature(adt_const_params, generic_const_exprs)]
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
+   |                                                    ^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
 
diff --git a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs
index 5673f1dd073..ffa9d960e04 100644
--- a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs
+++ b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs
@@ -7,7 +7,8 @@
 pub fn foo()
 where
     for<const N: usize = { const fn bar() {} bar(); 1 }> ():,
-    //~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
+    //~^ ERROR late-bound const parameters cannot be used currently
+    //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders
 {}
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr
index 5924a673da9..814022f26b9 100644
--- a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr
@@ -1,8 +1,14 @@
+error: late-bound const parameters cannot be used currently
+  --> $DIR/no-entry-found-for-key-ice-gce-nlb-113133.rs:9:15
+   |
+LL |     for<const N: usize = { const fn bar() {} bar(); 1 }> ():,
+   |               ^
+
 error: defaults for generic parameters are not allowed in `for<...>` binders
   --> $DIR/no-entry-found-for-key-ice-gce-nlb-113133.rs:9:9
    |
 LL |     for<const N: usize = { const fn bar() {} bar(); 1 }> ():,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
index 5e4acd80e93..2a6d9f53317 100644
--- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
+++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
@@ -1,14 +1,14 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:14:45
    |
-LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
-   |                                            ^ cannot perform const operation using `T`
+LL |     T: Trait<{ std::intrinsics::type_name::<T>() }>,
+   |                                             ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:9:22
    |
 LL | trait Trait<const S: &'static str> {}
    |                      ^^^^^^^^^^^^
@@ -18,6 +18,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs
index 02e6d27a27e..79c20fe81e3 100644
--- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs
+++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs
@@ -2,8 +2,7 @@
 //@ revisions: full min
 
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(full, feature(adt_const_params, generic_const_exprs))]
-
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params, generic_const_exprs))]
 #![feature(core_intrinsics)]
 #![feature(const_type_name)]
 
@@ -12,10 +11,10 @@ trait Trait<const S: &'static str> {}
 
 struct Bug<T>
 where
-    T: Trait<{std::intrinsics::type_name::<T>()}>
+    T: Trait<{ std::intrinsics::type_name::<T>() }>,
     //[min]~^ ERROR generic parameters may not be used in const operations
 {
-    t: T
+    t: T,
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/issue-66451.rs b/tests/ui/const-generics/issue-66451.rs
index c8d5515e987..0b8693e0e67 100644
--- a/tests/ui/const-generics/issue-66451.rs
+++ b/tests/ui/const-generics/issue-66451.rs
@@ -1,30 +1,20 @@
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
-use std::marker::ConstParamTy;
+use std::marker::UnsizedConstParamTy;
 
-#[derive(Debug, PartialEq, Eq, ConstParamTy)]
+#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)]
 struct Foo {
     value: i32,
     nested: &'static Bar<i32>,
 }
 
-#[derive(Debug, PartialEq, Eq, ConstParamTy)]
+#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)]
 struct Bar<T>(T);
 
 struct Test<const F: Foo>;
 
 fn main() {
-    let x: Test<{
-        Foo {
-            value: 3,
-            nested: &Bar(4),
-        }
-    }> = Test;
-    let y: Test<{
-        Foo {
-            value: 3,
-            nested: &Bar(5),
-        }
-    }> = x; //~ ERROR mismatched types
+    let x: Test<{ Foo { value: 3, nested: &Bar(4) } }> = Test;
+    let y: Test<{ Foo { value: 3, nested: &Bar(5) } }> = x; //~ ERROR mismatched types
 }
diff --git a/tests/ui/const-generics/issue-66451.stderr b/tests/ui/const-generics/issue-66451.stderr
index 404e3839bca..63d193e1bca 100644
--- a/tests/ui/const-generics/issue-66451.stderr
+++ b/tests/ui/const-generics/issue-66451.stderr
@@ -1,16 +1,10 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-66451.rs:29:10
+  --> $DIR/issue-66451.rs:19:58
    |
-LL |       let y: Test<{
-   |  ____________-
-LL | |         Foo {
-LL | |             value: 3,
-LL | |             nested: &Bar(5),
-LL | |         }
-LL | |     }> = x;
-   | |      -   ^ expected `Foo { value: 3, nested: &Bar::<i32>(5) }`, found `Foo { value: 3, nested: &Bar::<i32>(4) }`
-   | |______|
-   |        expected due to this
+LL |     let y: Test<{ Foo { value: 3, nested: &Bar(5) } }> = x;
+   |            -------------------------------------------   ^ expected `Foo { value: 3, nested: &Bar::<i32>(5) }`, found `Foo { value: 3, nested: &Bar::<i32>(4) }`
+   |            |
+   |            expected due to this
    |
    = note: expected struct `Test<Foo { value: 3, nested: &Bar::<i32>(5) }>`
               found struct `Test<Foo { value: 3, nested: &Bar::<i32>(4) }>`
diff --git a/tests/ui/const-generics/issue-70408.rs b/tests/ui/const-generics/issue-70408.rs
index e74bcf945a5..ea7a57d3b2f 100644
--- a/tests/ui/const-generics/issue-70408.rs
+++ b/tests/ui/const-generics/issue-70408.rs
@@ -1,6 +1,6 @@
 //@ build-pass
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
diff --git a/tests/ui/const-generics/issue-80471.rs b/tests/ui/const-generics/issue-80471.rs
index fa6f1fde435..20d92092b9f 100644
--- a/tests/ui/const-generics/issue-80471.rs
+++ b/tests/ui/const-generics/issue-80471.rs
@@ -1,5 +1,4 @@
 #![feature(adt_const_params)]
-//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
 
 #[derive(PartialEq, Eq)]
 enum Nat {
diff --git a/tests/ui/const-generics/issue-80471.stderr b/tests/ui/const-generics/issue-80471.stderr
index b21ad3aec79..a8514c5cc07 100644
--- a/tests/ui/const-generics/issue-80471.stderr
+++ b/tests/ui/const-generics/issue-80471.stderr
@@ -1,14 +1,5 @@
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-80471.rs:1:12
-   |
-LL | #![feature(adt_const_params)]
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
 error[E0741]: `Nat` must implement `ConstParamTy` to be used as the type of a const generic parameter
-  --> $DIR/issue-80471.rs:10:17
+  --> $DIR/issue-80471.rs:9:17
    |
 LL | fn foo<const N: Nat>() {}
    |                 ^^^
@@ -19,6 +10,6 @@ LL + #[derive(ConstParamTy)]
 LL | enum Nat {
    |
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0741`.
diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs
index 4e9d3626aa8..e07fde76a4a 100644
--- a/tests/ui/const-generics/issues/issue-100313.rs
+++ b/tests/ui/const-generics/issues/issue-100313.rs
@@ -1,10 +1,10 @@
 #![allow(incomplete_features)]
 #![feature(const_mut_refs)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 struct T<const B: &'static bool>;
 
-impl <const B: &'static bool> T<B> {
+impl<const B: &'static bool> T<B> {
     const fn set_false(&self) {
         unsafe {
             *(B as *const bool as *mut bool) = false;
@@ -14,7 +14,7 @@ impl <const B: &'static bool> T<B> {
 }
 
 const _: () = {
-    let x = T::<{&true}>;
+    let x = T::<{ &true }>;
     x.set_false();
 };
 
diff --git a/tests/ui/const-generics/issues/issue-105821.rs b/tests/ui/const-generics/issues/issue-105821.rs
index ecbae4d9f35..3092893837a 100644
--- a/tests/ui/const-generics/issues/issue-105821.rs
+++ b/tests/ui/const-generics/issues/issue-105821.rs
@@ -4,7 +4,7 @@
 // a failing test, we just started masking the bug.
 
 #![allow(incomplete_features)]
-#![feature(adt_const_params, generic_const_exprs)]
+#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
 #![allow(dead_code)]
 
 const fn catone<const M: usize>(_a: &[u8; M]) -> [u8; M + 1]
diff --git a/tests/ui/const-generics/issues/issue-56445-1.min.stderr b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
index 580542bb6da..ff0a1bfc0b5 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.min.stderr
+++ b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
@@ -17,6 +17,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-56445-1.rs b/tests/ui/const-generics/issues/issue-56445-1.rs
index 35126b3f55a..53aab40b0ad 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.rs
+++ b/tests/ui/const-generics/issues/issue-56445-1.rs
@@ -1,6 +1,6 @@
 // Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995.
 //@ revisions: full min
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
 #![crate_type = "lib"]
 
diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr
index 5082705927e..8ea96428deb 100644
--- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr
+++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr
@@ -4,7 +4,7 @@ error[E0741]: `&'static (dyn A + 'static)` can't be used as a const parameter ty
 LL | fn test<const T: &'static dyn A>() {
    |                  ^^^^^^^^^^^^^^
    |
-   = note: `(dyn A + 'static)` must implement `ConstParamTy`, but it does not
+   = note: `(dyn A + 'static)` must implement `UnsizedConstParamTy`, but it does not
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
index 7f387cbd5a1..101ca456cd9 100644
--- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
+++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
@@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs
index c5b83e9d529..9b15a8a7013 100644
--- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs
+++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs
@@ -1,5 +1,5 @@
 //@ revisions: full min
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
 
 trait A {}
diff --git a/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs b/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs
index 113bf94b5cb..41c5eaa0cd9 100644
--- a/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs
+++ b/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs
@@ -1,8 +1,7 @@
 //@ check-pass
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
-
 trait Trait<const NAME: &'static str> {
     type Assoc;
 }
diff --git a/tests/ui/const-generics/issues/issue-71547.rs b/tests/ui/const-generics/issues/issue-71547.rs
index a2cea433a44..bb9ca63bd32 100644
--- a/tests/ui/const-generics/issues/issue-71547.rs
+++ b/tests/ui/const-generics/issues/issue-71547.rs
@@ -1,6 +1,6 @@
 //@ check-pass
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 pub trait GetType<const N: &'static str> {
diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
index e9363d42148..cba03b1cb1f 100644
--- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
+++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
@@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs
index 701b3423f31..fcab1f70507 100644
--- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs
+++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs
@@ -3,12 +3,12 @@
 //@ revisions: full min
 //@[full]check-pass
 
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
 
 fn a<const X: &'static [u32]>() {}
 //[min]~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter
 
 fn main() {
-    a::<{&[]}>();
+    a::<{ &[] }>();
 }
diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs
index bd9431dbc85..ab68c6b78df 100644
--- a/tests/ui/const-generics/issues/issue-86535-2.rs
+++ b/tests/ui/const-generics/issues/issue-86535-2.rs
@@ -1,10 +1,12 @@
 //@ run-pass
-#![feature(adt_const_params, generic_const_exprs)]
+#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
 #![allow(incomplete_features)]
 
 pub trait Foo {
     const ASSOC_C: usize;
-    fn foo() where [(); Self::ASSOC_C]:;
+    fn foo()
+    where
+        [(); Self::ASSOC_C]:;
 }
 
 #[allow(dead_code)]
@@ -12,7 +14,10 @@ struct Bar<const N: &'static ()>;
 impl<const N: &'static ()> Foo for Bar<N> {
     const ASSOC_C: usize = 3;
 
-    fn foo() where [u8; Self::ASSOC_C]: {
+    fn foo()
+    where
+        [u8; Self::ASSOC_C]:,
+    {
         let _: [u8; Self::ASSOC_C] = loop {};
     }
 }
diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs
index cd9934a4a99..9aaf7ddc9e8 100644
--- a/tests/ui/const-generics/issues/issue-86535.rs
+++ b/tests/ui/const-generics/issues/issue-86535.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-#![feature(adt_const_params, generic_const_exprs)]
+#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
 #![allow(incomplete_features, unused_variables)]
 
 #[allow(dead_code)]
diff --git a/tests/ui/const-generics/issues/issue-90455.fixed b/tests/ui/const-generics/issues/issue-90455.fixed
index 2502d47eb46..423a1fbd765 100644
--- a/tests/ui/const-generics/issues/issue-90455.fixed
+++ b/tests/ui/const-generics/issues/issue-90455.fixed
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![feature(generic_const_exprs, adt_const_params)]
+#![feature(generic_const_exprs, unsized_const_params, adt_const_params)]
 #![allow(incomplete_features, dead_code)]
 
 struct FieldElement<const N: &'static str> where [(); num_limbs(N)]: {
diff --git a/tests/ui/const-generics/issues/issue-90455.rs b/tests/ui/const-generics/issues/issue-90455.rs
index 794c7d76cb1..be4f27ec689 100644
--- a/tests/ui/const-generics/issues/issue-90455.rs
+++ b/tests/ui/const-generics/issues/issue-90455.rs
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![feature(generic_const_exprs, adt_const_params)]
+#![feature(generic_const_exprs, unsized_const_params, adt_const_params)]
 #![allow(incomplete_features, dead_code)]
 
 struct FieldElement<const N: &'static str> {
diff --git a/tests/ui/const-generics/issues/issue-99641.stderr b/tests/ui/const-generics/issues/issue-99641.stderr
index 800aec3ef2c..3365012a038 100644
--- a/tests/ui/const-generics/issues/issue-99641.stderr
+++ b/tests/ui/const-generics/issues/issue-99641.stderr
@@ -4,7 +4,7 @@ error[E0741]: `(fn(),)` can't be used as a const parameter type
 LL |     pub struct Color<const WHITE: (fn(),)>;
    |                                   ^^^^^^^
    |
-   = note: `fn()` must implement `ConstParamTy`, but it does not
+   = note: `fn()` must implement `ConstParamTy_`, but it does not
 
 error[E0741]: `(fn(),)` can't be used as a const parameter type
   --> $DIR/issue-99641.rs:8:23
@@ -12,7 +12,7 @@ error[E0741]: `(fn(),)` can't be used as a const parameter type
 LL |     impl<const WHITE: (fn(),)> Color<WHITE> {
    |                       ^^^^^^^
    |
-   = note: `fn()` must implement `ConstParamTy`, but it does not
+   = note: `fn()` must implement `ConstParamTy_`, but it does not
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/min_const_generics/complex-types.stderr b/tests/ui/const-generics/min_const_generics/complex-types.stderr
index 8e83ea58194..0211770f9e5 100644
--- a/tests/ui/const-generics/min_const_generics/complex-types.stderr
+++ b/tests/ui/const-generics/min_const_generics/complex-types.stderr
@@ -45,6 +45,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `!` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:17:21
diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr
new file mode 100644
index 00000000000..18f47f7dc23
--- /dev/null
+++ b/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr
@@ -0,0 +1,15 @@
+error[E0741]: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:11:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+
+error[E0741]: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:13:15
+   |
+LL | impl<const P: *const u32> Const<P> {
+   |               ^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr
index 657eee2be24..18f47f7dc23 100644
--- a/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr
@@ -1,11 +1,11 @@
 error[E0741]: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:9:23
+  --> $DIR/raw-ptr-const-param-deref.rs:11:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
 
 error[E0741]: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:11:15
+  --> $DIR/raw-ptr-const-param-deref.rs:13:15
    |
 LL | impl<const P: *const u32> Const<P> {
    |               ^^^^^^^^^^
diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
index 1eb238255ab..6027dbb01cd 100644
--- a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
@@ -1,5 +1,5 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:9:23
+  --> $DIR/raw-ptr-const-param-deref.rs:11:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | struct Const<const P: *const u32>;
    = note: the only supported types are integers, `bool` and `char`
 
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:11:15
+  --> $DIR/raw-ptr-const-param-deref.rs:13:15
    |
 LL | impl<const P: *const u32> Const<P> {
    |               ^^^^^^^^^^
diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.rs b/tests/ui/const-generics/raw-ptr-const-param-deref.rs
index b7fcbb3447a..bf077acd4fa 100644
--- a/tests/ui/const-generics/raw-ptr-const-param-deref.rs
+++ b/tests/ui/const-generics/raw-ptr-const-param-deref.rs
@@ -1,21 +1,22 @@
 // Checks that pointers must not be used as the type of const params.
-//@ revisions: full min
+//@ revisions: min adt_const_params full
 
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(adt_const_params, feature(adt_const_params))]
+#![cfg_attr(adt_const_params, allow(incomplete_features))]
 
 const A: u32 = 3;
 
 struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
-impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters
+impl<const P: *const u32> Const<P> {
+    //~^ ERROR: using raw pointers as const generic parameters
     fn get() -> u32 {
-        unsafe {
-            *P
-        }
+        unsafe { *P }
     }
 }
 
 fn main() {
-    assert_eq!(Const::<{&A as *const _}>::get(), 3)
+    assert_eq!(Const::<{ &A as *const _ }>::get(), 3)
 }
diff --git a/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr b/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr
new file mode 100644
index 00000000000..f040d3cc36a
--- /dev/null
+++ b/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr
@@ -0,0 +1,21 @@
+error[E0741]: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param.rs:8:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/raw-ptr-const-param.rs:11:40
+   |
+LL |     let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
+   |            -------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `Const<{0xf as *const u32}>`
+              found struct `Const<{0xa as *const u32}>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0741.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/raw-ptr-const-param.full.stderr b/tests/ui/const-generics/raw-ptr-const-param.full.stderr
index 7ba9ac15bf3..f040d3cc36a 100644
--- a/tests/ui/const-generics/raw-ptr-const-param.full.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param.full.stderr
@@ -1,11 +1,11 @@
 error[E0741]: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param.rs:6:23
+  --> $DIR/raw-ptr-const-param.rs:8:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/raw-ptr-const-param.rs:9:40
+  --> $DIR/raw-ptr-const-param.rs:11:40
    |
 LL |     let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
    |            -------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
diff --git a/tests/ui/const-generics/raw-ptr-const-param.min.stderr b/tests/ui/const-generics/raw-ptr-const-param.min.stderr
index 18bbcc33c4d..c48eea069e0 100644
--- a/tests/ui/const-generics/raw-ptr-const-param.min.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param.min.stderr
@@ -1,5 +1,5 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param.rs:6:23
+  --> $DIR/raw-ptr-const-param.rs:8:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | struct Const<const P: *const u32>;
    = note: the only supported types are integers, `bool` and `char`
 
 error[E0308]: mismatched types
-  --> $DIR/raw-ptr-const-param.rs:9:40
+  --> $DIR/raw-ptr-const-param.rs:11:40
    |
 LL |     let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
    |            -------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
diff --git a/tests/ui/const-generics/raw-ptr-const-param.rs b/tests/ui/const-generics/raw-ptr-const-param.rs
index 19d18a2f9d2..49e48d9905f 100644
--- a/tests/ui/const-generics/raw-ptr-const-param.rs
+++ b/tests/ui/const-generics/raw-ptr-const-param.rs
@@ -1,7 +1,9 @@
-//@ revisions: full min
+//@ revisions: min adt_const_params full
 
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(adt_const_params, feature(adt_const_params))]
+#![cfg_attr(adt_const_params, allow(incomplete_features))]
 
 struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
diff --git a/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr
new file mode 100644
index 00000000000..bcb2bd255da
--- /dev/null
+++ b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr
@@ -0,0 +1,49 @@
+error[E0741]: `&'static str` can't be used as a const parameter type
+  --> $DIR/slice-const-param-mismatch.rs:8:29
+   |
+LL | struct ConstString<const T: &'static str>;
+   |                             ^^^^^^^^^^^^
+
+error[E0741]: `&'static [u8]` can't be used as a const parameter type
+  --> $DIR/slice-const-param-mismatch.rs:11:28
+   |
+LL | struct ConstBytes<const T: &'static [u8]>;
+   |                            ^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/slice-const-param-mismatch.rs:17:35
+   |
+LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
+   |            --------------------   ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `ConstString<"Hello">`
+              found struct `ConstString<"World">`
+
+error[E0308]: mismatched types
+  --> $DIR/slice-const-param-mismatch.rs:19:33
+   |
+LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
+   |            -------------------   ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `ConstString<"ℇ㇈↦">`
+              found struct `ConstString<"ℇ㇈↥">`
+
+error[E0308]: mismatched types
+  --> $DIR/slice-const-param-mismatch.rs:21:33
+   |
+LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
+   |            ------------------   ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `ConstBytes<b"AAA">`
+              found struct `ConstBytes<b"BBB">`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0308, E0741.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/slice-const-param-mismatch.full.stderr b/tests/ui/const-generics/slice-const-param-mismatch.full.stderr
index 80dd1be33c2..883ba988be7 100644
--- a/tests/ui/const-generics/slice-const-param-mismatch.full.stderr
+++ b/tests/ui/const-generics/slice-const-param-mismatch.full.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:14:35
+  --> $DIR/slice-const-param-mismatch.rs:17:35
    |
 LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
    |            --------------------   ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
@@ -10,7 +10,7 @@ LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
               found struct `ConstString<"World">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:16:33
+  --> $DIR/slice-const-param-mismatch.rs:19:33
    |
 LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
    |            -------------------   ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
@@ -21,7 +21,7 @@ LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
               found struct `ConstString<"ℇ㇈↥">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:18:33
+  --> $DIR/slice-const-param-mismatch.rs:21:33
    |
 LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
    |            ------------------   ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
diff --git a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
index 0650dafc685..3b2410c9894 100644
--- a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
+++ b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
@@ -1,5 +1,5 @@
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/slice-const-param-mismatch.rs:7:29
+  --> $DIR/slice-const-param-mismatch.rs:8:29
    |
 LL | struct ConstString<const T: &'static str>;
    |                             ^^^^^^^^^^^^
@@ -9,9 +9,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `&'static [u8]` is forbidden as the type of a const generic parameter
-  --> $DIR/slice-const-param-mismatch.rs:9:28
+  --> $DIR/slice-const-param-mismatch.rs:11:28
    |
 LL | struct ConstBytes<const T: &'static [u8]>;
    |                            ^^^^^^^^^^^^^
@@ -21,9 +25,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:14:35
+  --> $DIR/slice-const-param-mismatch.rs:17:35
    |
 LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
    |            --------------------   ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
@@ -34,7 +42,7 @@ LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
               found struct `ConstString<"World">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:16:33
+  --> $DIR/slice-const-param-mismatch.rs:19:33
    |
 LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
    |            -------------------   ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
@@ -45,7 +53,7 @@ LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
               found struct `ConstString<"ℇ㇈↥">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:18:33
+  --> $DIR/slice-const-param-mismatch.rs:21:33
    |
 LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
    |            ------------------   ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
diff --git a/tests/ui/const-generics/slice-const-param-mismatch.rs b/tests/ui/const-generics/slice-const-param-mismatch.rs
index 733eeb69fa9..feee39e602d 100644
--- a/tests/ui/const-generics/slice-const-param-mismatch.rs
+++ b/tests/ui/const-generics/slice-const-param-mismatch.rs
@@ -1,19 +1,22 @@
-//@ revisions: full min
+//@ revisions: min adt_const_params full
 
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
-
+#![cfg_attr(adt_const_params, feature(adt_const_params))]
+#![cfg_attr(adt_const_params, allow(incomplete_features))]
 
 struct ConstString<const T: &'static str>;
 //[min]~^ ERROR
+//[adt_const_params]~^^ ERROR
 struct ConstBytes<const T: &'static [u8]>;
 //[min]~^ ERROR
+//[adt_const_params]~^^ ERROR
 
 pub fn main() {
     let _: ConstString<"Hello"> = ConstString::<"Hello">;
     let _: ConstString<"Hello"> = ConstString::<"World">; //~ ERROR mismatched types
     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↦">;
     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //~ ERROR mismatched types
-    let _: ConstBytes<b"AAA"> = ConstBytes::<{&[0x41, 0x41, 0x41]}>;
+    let _: ConstBytes<b"AAA"> = ConstBytes::<{ &[0x41, 0x41, 0x41] }>;
     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; //~ ERROR mismatched types
 }
diff --git a/tests/ui/const-generics/slice-const-param.rs b/tests/ui/const-generics/slice-const-param.rs
index c6c0047c929..1c5088b5283 100644
--- a/tests/ui/const-generics/slice-const-param.rs
+++ b/tests/ui/const-generics/slice-const-param.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 pub fn function_with_str<const STRING: &'static str>() -> &'static str {
@@ -12,9 +12,8 @@ pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
 }
 
 // Also check the codepaths for custom DST
-#[derive(PartialEq, Eq)]
+#[derive(std::marker::UnsizedConstParamTy, PartialEq, Eq)]
 struct MyStr(str);
-impl std::marker::ConstParamTy for MyStr {}
 
 fn function_with_my_str<const S: &'static MyStr>() -> &'static MyStr {
     S
@@ -34,7 +33,7 @@ pub fn main() {
     assert_eq!(function_with_str::<"Rust">(), "Rust");
     assert_eq!(function_with_str::<"ℇ㇈↦">(), "ℇ㇈↦");
     assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
-    assert_eq!(function_with_bytes::<{&[0x41, 0x41, 0x41, 0x41]}>(), b"AAAA");
+    assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA");
 
     assert_eq!(function_with_my_str::<{ MyStr::new("hello") }>().as_str(), "hello");
 }
diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr
new file mode 100644
index 00000000000..7a936ced030
--- /dev/null
+++ b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr
@@ -0,0 +1,9 @@
+error[E0741]: `&'static ()` can't be used as a const parameter type
+  --> $DIR/transmute-const-param-static-reference.rs:9:23
+   |
+LL | struct Const<const P: &'static ()>;
+   |                       ^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
index fdb6ddeb578..cf236487cf0 100644
--- a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
+++ b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
@@ -1,5 +1,5 @@
 error: `&'static ()` is forbidden as the type of a const generic parameter
-  --> $DIR/transmute-const-param-static-reference.rs:7:23
+  --> $DIR/transmute-const-param-static-reference.rs:9:23
    |
 LL | struct Const<const P: &'static ()>;
    |                       ^^^^^^^^^^^
@@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.rs b/tests/ui/const-generics/transmute-const-param-static-reference.rs
index 49541233ed1..0b47fd31eaf 100644
--- a/tests/ui/const-generics/transmute-const-param-static-reference.rs
+++ b/tests/ui/const-generics/transmute-const-param-static-reference.rs
@@ -1,16 +1,17 @@
-//@ revisions: full min
+//@ revisions: full adt_const_params min
 //@[full] check-pass
 
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(adt_const_params, feature(adt_const_params))]
+#![cfg_attr(adt_const_params, allow(incomplete_features))]
 
 struct Const<const P: &'static ()>;
 //[min]~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
+//[adt_const_params]~^^ ERROR `&'static ()` can't be used as a const parameter type
 
 fn main() {
-    const A: &'static () = unsafe {
-        std::mem::transmute(10 as *const ())
-    };
+    const A: &'static () = unsafe { std::mem::transmute(10 as *const ()) };
 
-    let _ = Const::<{A}>;
+    let _ = Const::<{ A }>;
 }
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
index f42a331a8a4..858900a500d 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
@@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/issue-71348.rs:18:25
@@ -21,6 +25,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs
index f349a88d124..2ffbd015485 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.rs
+++ b/tests/ui/const-generics/type-dependent/issue-71348.rs
@@ -1,6 +1,6 @@
 //@ [full] run-pass
 //@ revisions: full min
-#![cfg_attr(full, feature(adt_const_params))]
+#![cfg_attr(full, feature(adt_const_params, unsized_const_params))]
 #![cfg_attr(full, allow(incomplete_features))]
 
 struct Foo {
diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.rs b/tests/ui/consts/refs_check_const_eq-issue-88384.rs
index fb0405b651c..46cb6275171 100644
--- a/tests/ui/consts/refs_check_const_eq-issue-88384.rs
+++ b/tests/ui/consts/refs_check_const_eq-issue-88384.rs
@@ -1,10 +1,10 @@
 #![feature(fn_traits)]
-#![feature(adt_const_params)]
-//~^ WARNING the feature `adt_const_params` is incomplete
+#![feature(adt_const_params, unsized_const_params)]
+//~^ WARNING the feature `unsized_const_params` is incomplete
 
 #[derive(PartialEq, Eq)]
-struct CompileTimeSettings{
-    hooks: &'static[fn()],
+struct CompileTimeSettings {
+    hooks: &'static [fn()],
 }
 
 struct Foo<const T: CompileTimeSettings>;
@@ -12,14 +12,11 @@ struct Foo<const T: CompileTimeSettings>;
 
 impl<const T: CompileTimeSettings> Foo<T> {
     //~^ ERROR `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter
-    fn call_hooks(){
-    }
+    fn call_hooks() {}
 }
 
-fn main(){
-    const SETTINGS: CompileTimeSettings = CompileTimeSettings{
-        hooks: &[],
-    };
+fn main() {
+    const SETTINGS: CompileTimeSettings = CompileTimeSettings { hooks: &[] };
 
     Foo::<SETTINGS>::call_hooks();
 }
diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr
index c490cd053e7..62c5c527641 100644
--- a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr
+++ b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr
@@ -1,8 +1,8 @@
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/refs_check_const_eq-issue-88384.rs:2:12
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/refs_check_const_eq-issue-88384.rs:2:30
    |
-LL | #![feature(adt_const_params)]
-   |            ^^^^^^^^^^^^^^^^
+LL | #![feature(adt_const_params, unsized_const_params)]
+   |                              ^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
    = note: `#[warn(incomplete_features)]` on by default
@@ -16,7 +16,7 @@ LL | struct Foo<const T: CompileTimeSettings>;
 help: add `#[derive(ConstParamTy)]` to the struct
    |
 LL + #[derive(ConstParamTy)]
-LL | struct CompileTimeSettings{
+LL | struct CompileTimeSettings {
    |
 
 error[E0741]: `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter
@@ -28,7 +28,7 @@ LL | impl<const T: CompileTimeSettings> Foo<T> {
 help: add `#[derive(ConstParamTy)]` to the struct
    |
 LL + #[derive(ConstParamTy)]
-LL | struct CompileTimeSettings{
+LL | struct CompileTimeSettings {
    |
 
 error: aborting due to 2 previous errors; 1 warning emitted
diff --git a/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs
index 446fdc75514..33b6b7f52ca 100644
--- a/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs
+++ b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 struct FooConst<const ARRAY: &'static [&'static str]> {}
 
diff --git a/tests/ui/error-codes/E0771.rs b/tests/ui/error-codes/E0771.rs
index c0a2e98a7df..a932c5ef981 100644
--- a/tests/ui/error-codes/E0771.rs
+++ b/tests/ui/error-codes/E0771.rs
@@ -1,5 +1,5 @@
-#![feature(adt_const_params)]
-//~^ WARN the feature `adt_const_params` is incomplete
+#![feature(adt_const_params, unsized_const_params)]
+//~^ WARN the feature `unsized_const_params` is incomplete
 
 fn function_with_str<'a, const STRING: &'a str>() {} //~ ERROR E0770
 
diff --git a/tests/ui/error-codes/E0771.stderr b/tests/ui/error-codes/E0771.stderr
index e1384effe37..5e829e6f6d2 100644
--- a/tests/ui/error-codes/E0771.stderr
+++ b/tests/ui/error-codes/E0771.stderr
@@ -6,11 +6,11 @@ LL | fn function_with_str<'a, const STRING: &'a str>() {}
    |
    = note: lifetime parameters may not be used in the type of const parameters
 
-warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/E0771.rs:1:12
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/E0771.rs:1:30
    |
-LL | #![feature(adt_const_params)]
-   |            ^^^^^^^^^^^^^^^^
+LL | #![feature(adt_const_params, unsized_const_params)]
+   |                              ^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
    = note: `#[warn(incomplete_features)]` on by default
diff --git a/tests/ui/errors/wrong-target-spec.rs b/tests/ui/errors/wrong-target-spec.rs
new file mode 100644
index 00000000000..bc9038c1fab
--- /dev/null
+++ b/tests/ui/errors/wrong-target-spec.rs
@@ -0,0 +1,8 @@
+// The attentive may note the underscores in the target triple, making it invalid. This test
+// checks that such invalid target specs are rejected by the compiler.
+// See https://github.com/rust-lang/rust/issues/33329
+
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64_unknown-linux-musl
+
+fn main() {}
diff --git a/tests/ui/errors/wrong-target-spec.stderr b/tests/ui/errors/wrong-target-spec.stderr
new file mode 100644
index 00000000000..8b06f404078
--- /dev/null
+++ b/tests/ui/errors/wrong-target-spec.stderr
@@ -0,0 +1,2 @@
+error: Error loading target specification: Could not find specification for target "x86_64_unknown-linux-musl". Run `rustc --print target-list` for a list of built-in targets
+
diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
index fcb9b8a6fc5..649e936888b 100644
--- a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
+++ b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
@@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.rs b/tests/ui/feature-gates/feature-gate-unsized-const-params.rs
new file mode 100644
index 00000000000..d088d382377
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.rs
@@ -0,0 +1,6 @@
+struct Foo<const N: [u8]>;
+//~^ ERROR: `[u8]` is forbidden as the type of a const generic parameter
+//~| HELP: add `#![feature(adt_const_params)]` to the crate
+//~| HELP: add `#![feature(unsized_const_params)]` to the crate
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
new file mode 100644
index 00000000000..0a87f34f4f5
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
@@ -0,0 +1,18 @@
+error: `[u8]` is forbidden as the type of a const generic parameter
+  --> $DIR/feature-gate-unsized-const-params.rs:1:21
+   |
+LL | struct Foo<const N: [u8]>;
+   |                     ^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
+   |
+LL + #![feature(adt_const_params)]
+   |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
index 4205c5c5ef7..d1decc0c3f1 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
+++ b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
@@ -13,8 +13,8 @@ LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooer<T>
              Fooy
+             Fooer<T>
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/gat-in-trait-path.rs:32:5
@@ -31,8 +31,8 @@ LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooer<T>
              Fooy
+             Fooer<T>
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/gat-in-trait-path.rs:32:5
@@ -49,8 +49,8 @@ LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooer<T>
              Fooy
+             Fooer<T>
    = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A = &'a ()> + 'static)>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr
index 7f58f825702..bcc6382cf7c 100644
--- a/tests/ui/generic-associated-types/issue-79422.base.stderr
+++ b/tests/ui/generic-associated-types/issue-79422.base.stderr
@@ -29,8 +29,8 @@ LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead:
-             Source
              std::collections::BTreeMap<K, V>
+             Source
 
 error[E0038]: the trait `MapLike` cannot be made into an object
   --> $DIR/issue-79422.rs:44:13
@@ -47,8 +47,8 @@ LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead:
-             Source
              std::collections::BTreeMap<K, V>
+             Source
    = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-const-items/elided-lifetimes.stderr b/tests/ui/generic-const-items/elided-lifetimes.stderr
index 1d4a997ff60..85807a1b631 100644
--- a/tests/ui/generic-const-items/elided-lifetimes.stderr
+++ b/tests/ui/generic-const-items/elided-lifetimes.stderr
@@ -32,6 +32,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs
index a6dcad3face..00034fb9f44 100644
--- a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs
+++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs
@@ -1,6 +1,6 @@
 //@ check-pass
 
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 trait Bar<const FOO: &'static str> {}
diff --git a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs
index b6395258c89..9205f1e1632 100644
--- a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs
+++ b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 #![allow(incomplete_features)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 
 pub struct Element;
 
diff --git a/tests/ui/inference/ice-cannot-relate-region-109178.rs b/tests/ui/inference/ice-cannot-relate-region-109178.rs
index 3282f95a992..2e3953646ff 100644
--- a/tests/ui/inference/ice-cannot-relate-region-109178.rs
+++ b/tests/ui/inference/ice-cannot-relate-region-109178.rs
@@ -2,7 +2,7 @@
 
 #![allow(incomplete_features)]
 #![crate_type = "lib"]
-#![feature(adt_const_params, generic_const_exprs)]
+#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
 
 struct Changes<const CHANGES: &[&'static str]>
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index 70f06b4be60..e446345aedc 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -63,6 +63,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/lto/debuginfo-lto-alloc.rs b/tests/ui/lto/debuginfo-lto-alloc.rs
index 459103c354c..89043275329 100644
--- a/tests/ui/lto/debuginfo-lto-alloc.rs
+++ b/tests/ui/lto/debuginfo-lto-alloc.rs
@@ -9,7 +9,8 @@
 // that compilation is successful.
 
 //@ check-pass
-//@ compile-flags: --test -C debuginfo=2 -C lto=fat -C incremental=inc-fat
+//@ compile-flags: --test -C debuginfo=2 -C lto=fat
+//@ incremental
 
 extern crate alloc;
 
diff --git a/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs
new file mode 100644
index 00000000000..781443207ac
--- /dev/null
+++ b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs
@@ -0,0 +1,18 @@
+//@ run-pass
+
+#![feature(macro_metavar_expr_concat)]
+
+macro_rules! one_rep {
+    ( $($a:ident)* ) => {
+        $(
+            const ${concat($a, Z)}: i32 = 3;
+        )*
+    };
+}
+
+fn main() {
+    one_rep!(A B C);
+    assert_eq!(AZ, 3);
+    assert_eq!(BZ, 3);
+    assert_eq!(CZ, 3);
+}
diff --git a/tests/ui/mir/ice-mir-const-qualif-125837.rs b/tests/ui/mir/ice-mir-const-qualif-125837.rs
new file mode 100644
index 00000000000..a0f57caaba4
--- /dev/null
+++ b/tests/ui/mir/ice-mir-const-qualif-125837.rs
@@ -0,0 +1,17 @@
+// Test for ICE: mir_const_qualif: index out of bounds: the len is 0 but the index is 0
+// https://github.com/rust-lang/rust/issues/125837
+
+use std::fmt::Debug;
+
+trait Foo<Item> {}
+
+impl<Item, D: Debug + Clone> Foo for D {
+//~^ ERROR missing generics for trait `Foo`
+    fn foo<'a>(&'a self) -> impl Debug {
+    //~^ ERROR method `foo` is not a member of trait `Foo`
+        const { return }
+//~^ ERROR return statement outside of function body
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/mir/ice-mir-const-qualif-125837.stderr b/tests/ui/mir/ice-mir-const-qualif-125837.stderr
new file mode 100644
index 00000000000..003b327210b
--- /dev/null
+++ b/tests/ui/mir/ice-mir-const-qualif-125837.stderr
@@ -0,0 +1,41 @@
+error[E0407]: method `foo` is not a member of trait `Foo`
+  --> $DIR/ice-mir-const-qualif-125837.rs:10:5
+   |
+LL | /     fn foo<'a>(&'a self) -> impl Debug {
+LL | |
+LL | |         const { return }
+LL | |
+LL | |     }
+   | |_____^ not a member of trait `Foo`
+
+error[E0107]: missing generics for trait `Foo`
+  --> $DIR/ice-mir-const-qualif-125837.rs:8:30
+   |
+LL | impl<Item, D: Debug + Clone> Foo for D {
+   |                              ^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `Item`
+  --> $DIR/ice-mir-const-qualif-125837.rs:6:7
+   |
+LL | trait Foo<Item> {}
+   |       ^^^ ----
+help: add missing generic argument
+   |
+LL | impl<Item, D: Debug + Clone> Foo<Item> for D {
+   |                                 ++++++
+
+error[E0572]: return statement outside of function body
+  --> $DIR/ice-mir-const-qualif-125837.rs:12:17
+   |
+LL | /     fn foo<'a>(&'a self) -> impl Debug {
+LL | |
+LL | |         const { return }
+   | |               --^^^^^^-- the return is part of this body...
+LL | |
+LL | |     }
+   | |_____- ...not the enclosing function body
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0107, E0407, E0572.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr
index 6e50dfe6a26..9b57c895eea 100644
--- a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr
@@ -204,6 +204,7 @@ note: `Option<Void>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~             None => {},
@@ -349,6 +350,7 @@ LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[_, ..]` not covered
    |
    = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         [] => {},
@@ -484,6 +486,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `&Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &None => {},
@@ -502,6 +505,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
@@ -520,6 +524,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_) => {},
@@ -538,6 +543,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_a) => {},
@@ -589,6 +595,7 @@ LL |     match ref_never {
    |           ^^^^^^^^^ pattern `&_` not covered
    |
    = note: the matched value is of type `&!`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: references are always considered inhabited
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
@@ -609,6 +616,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Err(_) => {},
@@ -627,6 +635,7 @@ note: `Option<Result<!, !>>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Result<!, !>>`
+   = note: `Result<!, !>` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr
index a1239466c9c..f24ce154d14 100644
--- a/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr
@@ -5,6 +5,7 @@ LL |     match nevers {
    |           ^^^^^^ pattern `&[_, ..]` not covered
    |
    = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &[] => (),
diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.fixed b/tests/ui/rust-2024/unsafe-env-suggestion.fixed
index 1f3d2dc0a31..eba35180ef6 100644
--- a/tests/ui/rust-2024/unsafe-env-suggestion.fixed
+++ b/tests/ui/rust-2024/unsafe-env-suggestion.fixed
@@ -1,6 +1,6 @@
 //@ run-rustfix
 
-#![deny(deprecated_safe)]
+#![deny(deprecated_safe_2024)]
 
 use std::env;
 
diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.rs b/tests/ui/rust-2024/unsafe-env-suggestion.rs
index 3bd169973e3..c039d7f2583 100644
--- a/tests/ui/rust-2024/unsafe-env-suggestion.rs
+++ b/tests/ui/rust-2024/unsafe-env-suggestion.rs
@@ -1,6 +1,6 @@
 //@ run-rustfix
 
-#![deny(deprecated_safe)]
+#![deny(deprecated_safe_2024)]
 
 use std::env;
 
diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.stderr b/tests/ui/rust-2024/unsafe-env-suggestion.stderr
index 7c12f4aa5ed..3aa10a3bed6 100644
--- a/tests/ui/rust-2024/unsafe-env-suggestion.stderr
+++ b/tests/ui/rust-2024/unsafe-env-suggestion.stderr
@@ -9,8 +9,8 @@ LL |     env::set_var("FOO", "BAR");
 note: the lint level is defined here
   --> $DIR/unsafe-env-suggestion.rs:3:9
    |
-LL | #![deny(deprecated_safe)]
-   |         ^^^^^^^^^^^^^^^
+LL | #![deny(deprecated_safe_2024)]
+   |         ^^^^^^^^^^^^^^^^^^^^
 help: you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code
    |
 LL +     // TODO: Audit that the environment access only happens in single-threaded code.
diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs
index abceb08ecc5..aec75a67306 100644
--- a/tests/ui/simd/intrinsic/generic-elements.rs
+++ b/tests/ui/simd/intrinsic/generic-elements.rs
@@ -1,6 +1,6 @@
 //@ build-fail
 
-#![feature(repr_simd, intrinsics, rustc_attrs, adt_const_params)]
+#![feature(repr_simd, intrinsics, rustc_attrs, adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 #[repr(simd)]
@@ -14,8 +14,7 @@ struct i32x4(i32, i32, i32, i32);
 #[repr(simd)]
 #[derive(Copy, Clone)]
 #[allow(non_camel_case_types)]
-struct i32x8(i32, i32, i32, i32,
-             i32, i32, i32, i32);
+struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32);
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
@@ -28,8 +27,7 @@ struct f32x4(f32, f32, f32, f32);
 #[repr(simd)]
 #[derive(Copy, Clone)]
 #[allow(non_camel_case_types)]
-struct f32x8(f32, f32, f32, f32,
-             f32, f32, f32, f32);
+struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32);
 
 extern "rust-intrinsic" {
     fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
@@ -61,11 +59,11 @@ fn main() {
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
 
         simd_shuffle::<_, _, f32x2>(x, x, IDX2);
-//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
+        //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
         simd_shuffle::<_, _, f32x4>(x, x, IDX4);
-//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
+        //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
         simd_shuffle::<_, _, f32x8>(x, x, IDX8);
-//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
+        //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
 
         simd_shuffle::<_, _, i32x8>(x, x, IDX2);
         //~^ ERROR expected return type of length 2, found `i32x8` with length 8
@@ -85,11 +83,11 @@ fn main() {
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
 
         simd_shuffle_generic::<_, f32x2, I2>(x, x);
-//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
+        //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
         simd_shuffle_generic::<_, f32x4, I4>(x, x);
-//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
+        //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
         simd_shuffle_generic::<_, f32x8, I8>(x, x);
-//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
+        //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
 
         simd_shuffle_generic::<_, i32x8, I2>(x, x);
         //~^ ERROR expected return type of length 2, found `i32x8` with length 8
diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr
index 26e01344939..0788a7c17f9 100644
--- a/tests/ui/simd/intrinsic/generic-elements.stderr
+++ b/tests/ui/simd/intrinsic/generic-elements.stderr
@@ -1,125 +1,125 @@
 error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:46:9
+  --> $DIR/generic-elements.rs:44:9
    |
 LL |         simd_insert(0, 0, 0);
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64`
-  --> $DIR/generic-elements.rs:48:9
+  --> $DIR/generic-elements.rs:46:9
    |
 LL |         simd_insert(x, 0, 1.0);
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32`
-  --> $DIR/generic-elements.rs:50:9
+  --> $DIR/generic-elements.rs:48:9
    |
 LL |         simd_extract::<_, f32>(x, 0);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:54:9
+  --> $DIR/generic-elements.rs:52:9
    |
 LL |         simd_shuffle::<i32, _, i32>(0, 0, IDX2);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:57:9
+  --> $DIR/generic-elements.rs:55:9
    |
 LL |         simd_shuffle::<i32, _, i32>(0, 0, IDX4);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:60:9
+  --> $DIR/generic-elements.rs:58:9
    |
 LL |         simd_shuffle::<i32, _, i32>(0, 0, IDX8);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
-  --> $DIR/generic-elements.rs:63:9
+  --> $DIR/generic-elements.rs:61:9
    |
 LL |         simd_shuffle::<_, _, f32x2>(x, x, IDX2);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
-  --> $DIR/generic-elements.rs:65:9
+  --> $DIR/generic-elements.rs:63:9
    |
 LL |         simd_shuffle::<_, _, f32x4>(x, x, IDX4);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
-  --> $DIR/generic-elements.rs:67:9
+  --> $DIR/generic-elements.rs:65:9
    |
 LL |         simd_shuffle::<_, _, f32x8>(x, x, IDX8);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `i32x8` with length 8
-  --> $DIR/generic-elements.rs:70:9
+  --> $DIR/generic-elements.rs:68:9
    |
 LL |         simd_shuffle::<_, _, i32x8>(x, x, IDX2);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 4, found `i32x8` with length 8
-  --> $DIR/generic-elements.rs:72:9
+  --> $DIR/generic-elements.rs:70:9
    |
 LL |         simd_shuffle::<_, _, i32x8>(x, x, IDX4);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 8, found `i32x2` with length 2
-  --> $DIR/generic-elements.rs:74:9
+  --> $DIR/generic-elements.rs:72:9
    |
 LL |         simd_shuffle::<_, _, i32x2>(x, x, IDX8);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:78:9
+  --> $DIR/generic-elements.rs:76:9
    |
 LL |         simd_shuffle_generic::<i32, i32, I2>(0, 0);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:81:9
+  --> $DIR/generic-elements.rs:79:9
    |
 LL |         simd_shuffle_generic::<i32, i32, I4>(0, 0);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:84:9
+  --> $DIR/generic-elements.rs:82:9
    |
 LL |         simd_shuffle_generic::<i32, i32, I8>(0, 0);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
-  --> $DIR/generic-elements.rs:87:9
+  --> $DIR/generic-elements.rs:85:9
    |
 LL |         simd_shuffle_generic::<_, f32x2, I2>(x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
-  --> $DIR/generic-elements.rs:89:9
+  --> $DIR/generic-elements.rs:87:9
    |
 LL |         simd_shuffle_generic::<_, f32x4, I4>(x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
-  --> $DIR/generic-elements.rs:91:9
+  --> $DIR/generic-elements.rs:89:9
    |
 LL |         simd_shuffle_generic::<_, f32x8, I8>(x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 2, found `i32x8` with length 8
-  --> $DIR/generic-elements.rs:94:9
+  --> $DIR/generic-elements.rs:92:9
    |
 LL |         simd_shuffle_generic::<_, i32x8, I2>(x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 4, found `i32x8` with length 8
-  --> $DIR/generic-elements.rs:96:9
+  --> $DIR/generic-elements.rs:94:9
    |
 LL |         simd_shuffle_generic::<_, i32x8, I4>(x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 8, found `i32x2` with length 2
-  --> $DIR/generic-elements.rs:98:9
+  --> $DIR/generic-elements.rs:96:9
    |
 LL |         simd_shuffle_generic::<_, i32x2, I8>(x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs
index 379616884a1..30c345cb904 100644
--- a/tests/ui/simd/monomorphize-shuffle-index.rs
+++ b/tests/ui/simd/monomorphize-shuffle-index.rs
@@ -1,7 +1,7 @@
 //@[old]run-pass
 //@[generic_with_fn]run-pass
 //@ revisions: old generic generic_with_fn
-#![feature(repr_simd, intrinsics, adt_const_params, generic_const_exprs)]
+#![feature(repr_simd, intrinsics, adt_const_params, unsized_const_params, generic_const_exprs)]
 #![allow(incomplete_features)]
 
 extern "rust-intrinsic" {
diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs
index 70d9b933a76..7f64f6995a4 100644
--- a/tests/ui/statics/const_generics.rs
+++ b/tests/ui/statics/const_generics.rs
@@ -11,7 +11,7 @@
 //@[opt] compile-flags: -O
 
 #![feature(const_refs_to_static)]
-#![feature(adt_const_params)]
+#![feature(adt_const_params, unsized_const_params)]
 #![allow(incomplete_features)]
 
 static FOO: usize = 42;
diff --git a/tests/ui/symbol-names/const-generics-str-demangling.rs b/tests/ui/symbol-names/const-generics-str-demangling.rs
index 871f3694e00..87b1fdf8a47 100644
--- a/tests/ui/symbol-names/const-generics-str-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-str-demangling.rs
@@ -1,7 +1,7 @@
 //@ build-fail
 //@ compile-flags: -C symbol-mangling-version=v0 --crate-name=c
 //@ normalize-stderr-test: "c\[.*?\]" -> "c[HASH]"
-#![feature(adt_const_params, rustc_attrs)]
+#![feature(adt_const_params, unsized_const_params, rustc_attrs)]
 #![allow(incomplete_features)]
 
 pub struct Str<const S: &'static str>;
diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.rs b/tests/ui/symbol-names/const-generics-structural-demangling.rs
index 6c79ed7314c..9f5f31177b3 100644
--- a/tests/ui/symbol-names/const-generics-structural-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-structural-demangling.rs
@@ -3,10 +3,10 @@
 
 //@ normalize-stderr-test: "c\[[0-9a-f]+\]" -> "c[HASH]"
 
-#![feature(adt_const_params, decl_macro, rustc_attrs)]
+#![feature(adt_const_params, unsized_const_params, decl_macro, rustc_attrs)]
 #![allow(incomplete_features)]
 
-use std::marker::ConstParamTy;
+use std::marker::UnsizedConstParamTy;
 
 pub struct RefByte<const RB: &'static u8>;
 
@@ -14,7 +14,7 @@ pub struct RefByte<const RB: &'static u8>;
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::RefByte<{&123}>>)
-impl RefByte<{&123}> {}
+impl RefByte<{ &123 }> {}
 
 // FIXME(eddyb) this was supposed to be `RefMutZst` with `&mut []`,
 // but that is currently not allowed in const generics.
@@ -24,7 +24,7 @@ pub struct RefZst<const RMZ: &'static [u8; 0]>;
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::RefZst<{&[]}>>)
-impl RefZst<{&[]}> {}
+impl RefZst<{ &[] }> {}
 
 pub struct Array3Bytes<const A3B: [u8; 3]>;
 
@@ -32,7 +32,7 @@ pub struct Array3Bytes<const A3B: [u8; 3]>;
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>)
-impl Array3Bytes<{[1, 2, 3]}> {}
+impl Array3Bytes<{ [1, 2, 3] }> {}
 
 pub struct TupleByteBool<const TBB: (u8, bool)>;
 
@@ -40,9 +40,9 @@ pub struct TupleByteBool<const TBB: (u8, bool)>;
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::TupleByteBool<{(1, false)}>>)
-impl TupleByteBool<{(1, false)}> {}
+impl TupleByteBool<{ (1, false) }> {}
 
-#[derive(PartialEq, Eq, ConstParamTy)]
+#[derive(PartialEq, Eq, UnsizedConstParamTy)]
 pub enum MyOption<T> {
     Some(T),
     None,
@@ -56,7 +56,7 @@ pub struct OptionUsize<const OU: MyOption<usize>>;
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::None}>>)
-impl OptionUsize<{MyOption::None}> {}
+impl OptionUsize<{ MyOption::None }> {}
 
 // HACK(eddyb) the full mangling is only in `.stderr` because we can normalize
 // the `core` disambiguator hash away there, but not here.
@@ -64,9 +64,9 @@ impl OptionUsize<{MyOption::None}> {}
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::Some(0)}>>)
-impl OptionUsize<{MyOption::Some(0)}> {}
+impl OptionUsize<{ MyOption::Some(0) }> {}
 
-#[derive(PartialEq, Eq, ConstParamTy)]
+#[derive(PartialEq, Eq, UnsizedConstParamTy)]
 pub struct Foo {
     s: &'static str,
     ch: char,
@@ -78,12 +78,12 @@ pub struct Foo_<const F: Foo>;
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}>>)
-impl Foo_<{Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}> {}
+impl Foo_<{ Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] } }> {}
 
 // NOTE(eddyb) this tests specifically the use of disambiguators in field names,
 // using macros 2.0 hygiene to create a `struct` with conflicting field names.
 macro duplicate_field_name_test($x:ident) {
-    #[derive(PartialEq, Eq, ConstParamTy)]
+    #[derive(PartialEq, Eq, UnsizedConstParamTy)]
     pub struct Bar {
         $x: u8,
         x: u16,
@@ -94,7 +94,7 @@ macro duplicate_field_name_test($x:ident) {
     //~^ ERROR symbol-name
     //~| ERROR demangling
     //~| ERROR demangling-alt(<c::Bar_<{c::Bar { x: 123, x: 4096 }}>>)
-    impl Bar_<{Bar { $x: 123, x: 4096 }}> {}
+    impl Bar_<{ Bar { $x: 123, x: 4096 } }> {}
 }
 duplicate_field_name_test!(x);
 
diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs
index af47e84672f..94d79d56c59 100644
--- a/tests/ui/target-feature/gate.rs
+++ b/tests/ui/target-feature/gate.rs
@@ -21,6 +21,7 @@
 // gate-test-loongarch_target_feature
 // gate-test-lahfsahf_target_feature
 // gate-test-prfchw_target_feature
+// gate-test-s390x_target_feature
 
 #[target_feature(enable = "avx512bw")]
 //~^ ERROR: currently unstable
diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr
index 31198f73c20..a69020e6864 100644
--- a/tests/ui/target-feature/gate.stderr
+++ b/tests/ui/target-feature/gate.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/gate.rs:25:18
+  --> $DIR/gate.rs:26:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs
index fc64381b961..b61a21eab41 100644
--- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs
+++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs
@@ -18,7 +18,8 @@ trait TraitC {}
 fn foo<T>()
 where
     for<const N: u8 = { T::A }> T: TraitA<AsA = impl TraitB<AsB = impl TraitC>>,
-    //~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
+    //~^ ERROR late-bound const parameters cannot be used currently
+    //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders
     //~| ERROR `impl Trait` is not allowed in bounds
 {
 }
diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr
index a4a79413a9b..e891df3f0c0 100644
--- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr
+++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr
@@ -1,3 +1,9 @@
+error: late-bound const parameters cannot be used currently
+  --> $DIR/bad-suggestion-on-missing-assoc.rs:20:15
+   |
+LL |     for<const N: u8 = { T::A }> T: TraitA<AsA = impl TraitB<AsB = impl TraitC>>,
+   |               ^
+
 warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/bad-suggestion-on-missing-assoc.rs:1:12
    |
@@ -29,6 +35,6 @@ LL |     for<const N: u8 = { T::A }> T: TraitA<AsA = impl TraitB<AsB = impl Trai
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error: aborting due to 2 previous errors; 2 warnings emitted
+error: aborting due to 3 previous errors; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs
index c6bf0dc1f72..13f9f196970 100644
--- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs
+++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs
@@ -4,10 +4,11 @@
 pub fn bar()
 where
     for<const N: usize = {
+    //~^ ERROR late-bound const parameters cannot be used currently
+    //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders
     (||1usize)()
 }> V: IntoIterator
-//~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
-//~^^ ERROR cannot find type `V` in this scope
+//~^ ERROR cannot find type `V` in this scope
 {
 }
 
diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr
index edc55a3c8e6..d9e77dec794 100644
--- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr
+++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `V` in this scope
-  --> $DIR/binder-defaults-112547.rs:8:4
+  --> $DIR/binder-defaults-112547.rs:10:4
    |
 LL | }> V: IntoIterator
    |    ^ not found in this scope
@@ -9,6 +9,12 @@ help: you might be missing a type parameter
 LL | pub fn bar<V>()
    |           +++
 
+error: late-bound const parameters cannot be used currently
+  --> $DIR/binder-defaults-112547.rs:6:15
+   |
+LL |     for<const N: usize = {
+   |               ^
+
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/binder-defaults-112547.rs:1:12
    |
@@ -23,10 +29,12 @@ error: defaults for generic parameters are not allowed in `for<...>` binders
    |
 LL |       for<const N: usize = {
    |  _________^
+LL | |
+LL | |
 LL | |     (||1usize)()
 LL | | }> V: IntoIterator
    | |_^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs
index f33da416ad8..bdfe41ca11b 100644
--- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs
+++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs
@@ -5,8 +5,9 @@
 fn fun()
 where
     for<T = (), const N: usize = 1> ():,
-//~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
-//~| ERROR defaults for generic parameters are not allowed in `for<...>` binders
+    //~^ ERROR late-bound const parameters cannot be used currently
+    //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders
+    //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders
 {}
 
 fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr
index 7fe82f1f097..947dd3a73bf 100644
--- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr
+++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr
@@ -1,3 +1,9 @@
+error: late-bound const parameters cannot be used currently
+  --> $DIR/binder-defaults-119489.rs:7:23
+   |
+LL |     for<T = (), const N: usize = 1> ():,
+   |                       ^
+
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/binder-defaults-119489.rs:1:12
    |
@@ -27,5 +33,5 @@ error: defaults for generic parameters are not allowed in `for<...>` binders
 LL |     for<T = (), const N: usize = 1> ():,
    |                 ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 2 warnings emitted
+error: aborting due to 3 previous errors; 2 warnings emitted
 
diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs
new file mode 100644
index 00000000000..2d44388f875
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs
@@ -0,0 +1,11 @@
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+fn b()
+where
+    for<const C: usize> [(); C]: Copy,
+    //~^ ERROR late-bound const parameters cannot be used currently
+{
+}
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr
new file mode 100644
index 00000000000..136d533a03c
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr
@@ -0,0 +1,17 @@
+error: late-bound const parameters cannot be used currently
+  --> $DIR/late-const-param-wf.rs:6:15
+   |
+LL |     for<const C: usize> [(); C]: Copy,
+   |               ^
+
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/late-const-param-wf.rs:1:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr
index c30b6334fed..642a93d64e2 100644
--- a/tests/ui/try-trait/bad-interconversion.stderr
+++ b/tests/ui/try-trait/bad-interconversion.stderr
@@ -23,9 +23,7 @@ LL |     Some(3)?;
    |            ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
-   = help: the following other types implement trait `FromResidual<R>`:
-             `Result<T, F>` implements `FromResidual<Result<Infallible, E>>`
-             `Result<T, F>` implements `FromResidual<Yeet<E>>`
+   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
 
 error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
   --> $DIR/bad-interconversion.rs:17:31
@@ -36,9 +34,7 @@ LL |     Ok(ControlFlow::Break(123)?)
    |                               ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>`
    |
    = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
-   = help: the following other types implement trait `FromResidual<R>`:
-             `Result<T, F>` implements `FromResidual<Result<Infallible, E>>`
-             `Result<T, F>` implements `FromResidual<Yeet<E>>`
+   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
 
 error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
   --> $DIR/bad-interconversion.rs:22:22
@@ -49,9 +45,7 @@ LL |     Some(Err("hello")?)
    |                      ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
    |
    = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
-   = help: the following other types implement trait `FromResidual<R>`:
-             `Option<T>` implements `FromResidual<Yeet<()>>`
-             `Option<T>` implements `FromResidual`
+   = help: the trait `FromResidual` is implemented for `Option<T>`
 
 error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
   --> $DIR/bad-interconversion.rs:27:33
@@ -62,9 +56,7 @@ LL |     Some(ControlFlow::Break(123)?)
    |                                 ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
    |
    = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
-   = help: the following other types implement trait `FromResidual<R>`:
-             `Option<T>` implements `FromResidual<Yeet<()>>`
-             `Option<T>` implements `FromResidual`
+   = help: the trait `FromResidual` is implemented for `Option<T>`
 
 error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
   --> $DIR/bad-interconversion.rs:32:39
diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr
index 2d97226275d..8055b2a0b04 100644
--- a/tests/ui/try-trait/option-to-result.stderr
+++ b/tests/ui/try-trait/option-to-result.stderr
@@ -8,9 +8,7 @@ LL |     a?;
    |      ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
-   = help: the following other types implement trait `FromResidual<R>`:
-             `Result<T, F>` implements `FromResidual<Result<Infallible, E>>`
-             `Result<T, F>` implements `FromResidual<Yeet<E>>`
+   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
 
 error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
   --> $DIR/option-to-result.rs:11:6
@@ -22,9 +20,7 @@ LL |     a?;
    |      ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
    |
    = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
-   = help: the following other types implement trait `FromResidual<R>`:
-             `Option<T>` implements `FromResidual<Yeet<()>>`
-             `Option<T>` implements `FromResidual`
+   = help: the trait `FromResidual` is implemented for `Option<T>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/try-trait/try-on-option.stderr b/tests/ui/try-trait/try-on-option.stderr
index 84a51a078af..15d0b28ddc1 100644
--- a/tests/ui/try-trait/try-on-option.stderr
+++ b/tests/ui/try-trait/try-on-option.stderr
@@ -8,9 +8,7 @@ LL |     x?;
    |      ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
-   = help: the following other types implement trait `FromResidual<R>`:
-             `Result<T, F>` implements `FromResidual<Result<Infallible, E>>`
-             `Result<T, F>` implements `FromResidual<Yeet<E>>`
+   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
   --> $DIR/try-on-option.rs:11:6
diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr
index 08f1ede95b4..0479f134a38 100644
--- a/tests/ui/typeck/ice-unexpected-region-123863.stderr
+++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr
@@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/ice-unexpected-region-123863.rs:3:27
@@ -21,6 +25,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
    |
 LL + #![feature(adt_const_params)]
    |
+help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
+   |
+LL + #![feature(unsized_const_params)]
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/ice-unexpected-region-123863.rs:5:5
diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
index e30cb8ff921..8d5b377988c 100644
--- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
@@ -26,8 +26,8 @@ LL | trait Trait: Sized {}
    |       |
    |       this trait cannot be made into an object...
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Trait` for this new enum and using it instead:
-             R
              S
+             R
    = note: required for the cast from `&S` to `&dyn Trait`
 
 error[E0038]: the trait `Trait` cannot be made into an object
@@ -48,8 +48,8 @@ LL | trait Trait: Sized {}
    |       |
    |       this trait cannot be made into an object...
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Trait` for this new enum and using it instead:
-             R
              S
+             R
    = note: required for the cast from `&R` to `&dyn Trait`
 
 error: aborting due to 3 previous errors
diff --git a/triagebot.toml b/triagebot.toml
index 5335cf4e4bf..5c5aa475385 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -905,7 +905,7 @@ cc = ["@kobzol"]
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
-users_on_vacation = ["jyn514", "jhpratt", "oli-obk"]
+users_on_vacation = ["jyn514", "jhpratt", "oli-obk", "michaelwoerister"]
 
 [assign.adhoc_groups]
 compiler-team = [