about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-05-19 10:35:44 +0200
committerRalf Jung <post@ralfj.de>2024-05-19 10:35:44 +0200
commit3460853a453fb85a13ef6763ae01b2e64c9be7b7 (patch)
treefa91aa22e7d5b09dde4b55bbc4bb6c926bf8a2f2
parent1ba83f2dc11ce0f2249e597bb59839bb8ea8df6b (diff)
parent6579ed89f0fcc26da71afdd11d30d63f6f812a0a (diff)
downloadrust-3460853a453fb85a13ef6763ae01b2e64c9be7b7.tar.gz
rust-3460853a453fb85a13ef6763ae01b2e64c9be7b7.zip
Merge from rustc
-rw-r--r--Cargo.lock11
-rw-r--r--compiler/rustc_abi/src/layout.rs7
-rw-r--r--compiler/rustc_abi/src/lib.rs4
-rw-r--r--compiler/rustc_ast/src/ast.rs30
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs32
-rw-r--r--compiler/rustc_ast/src/token.rs4
-rw-r--r--compiler/rustc_ast/src/visit.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs24
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs26
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs19
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs6
-rw-r--r--compiler/rustc_expand/messages.ftl5
-rw-r--r--compiler/rustc_expand/src/config.rs9
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs40
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs3
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs17
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs71
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs30
-rw-r--r--compiler/rustc_hir/src/intravisit.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs43
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs6
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs24
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs42
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs26
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs12
-rw-r--r--compiler/rustc_infer/src/infer/relate/glb.rs5
-rw-r--r--compiler/rustc_infer/src/infer/relate/lub.rs5
-rw-r--r--compiler/rustc_infer/src/infer/relate/type_relating.rs5
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs4
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs12
-rw-r--r--compiler/rustc_infer/src/traits/util.rs14
-rw-r--r--compiler/rustc_lint/src/builtin.rs10
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs4
-rw-r--r--compiler/rustc_middle/Cargo.toml1
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs155
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs29
-rw-r--r--compiler/rustc_middle/src/traits/query.rs5
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs218
-rw-r--r--compiler/rustc_middle/src/traits/solve/cache.rs6
-rw-r--r--compiler/rustc_middle/src/traits/util.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs57
-rw-r--r--compiler/rustc_middle/src/ty/error.rs6
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs4
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs19
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs187
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs20
-rw-r--r--compiler/rustc_middle/src/ty/region.rs6
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs14
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs45
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs100
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs2
-rw-r--r--compiler/rustc_middle/src/ty/util.rs6
-rw-r--r--compiler/rustc_middle/src/values.rs2
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs4
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs2
-rw-r--r--compiler/rustc_next_trait_solver/Cargo.toml12
-rw-r--r--compiler/rustc_next_trait_solver/src/lib.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/solve.rs1
-rw-r--r--compiler/rustc_parse/src/parser/item.rs46
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs10
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs12
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs6
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs1
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs15
-rw-r--r--compiler/rustc_resolve/src/diagnostics/tests.rs40
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs1
-rw-r--r--compiler/rustc_resolve/src/ident.rs1
-rw-r--r--compiler/rustc_resolve/src/imports.rs1
-rw-r--r--compiler/rustc_resolve/src/late.rs1
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs1
-rw-r--r--compiler/rustc_resolve/src/lib.rs28
-rw-r--r--compiler/rustc_resolve/src/macros.rs6
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs1
-rw-r--r--compiler/rustc_session/src/config.rs1
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mod.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs8
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs7
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml4
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs45
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs33
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs209
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs21
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/build.rs196
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs39
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs10
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs4
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs141
-rw-r--r--compiler/rustc_type_ir/src/generic_arg.rs18
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs27
-rw-r--r--compiler/rustc_type_ir/src/interner.rs32
-rw-r--r--compiler/rustc_type_ir/src/ir_print.rs5
-rw-r--r--compiler/rustc_type_ir/src/lib.rs12
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs3
-rw-r--r--compiler/rustc_type_ir/src/solve.rs278
-rw-r--r--compiler/rustc_type_ir/src/solve/inspect.rs (renamed from compiler/rustc_middle/src/traits/solve/inspect.rs)137
-rw-r--r--compiler/rustc_type_ir/src/solve/inspect/format.rs (renamed from compiler/rustc_middle/src/traits/solve/inspect/format.rs)22
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs81
-rw-r--r--compiler/rustc_type_ir/src/upcast.rs24
-rw-r--r--compiler/stable_mir/src/mir/body.rs2
-rw-r--r--compiler/stable_mir/src/ty.rs7
-rw-r--r--config.example.toml9
-rw-r--r--library/alloc/src/boxed.rs48
-rw-r--r--library/alloc/src/string.rs22
-rw-r--r--library/core/src/convert/num.rs5
-rw-r--r--library/core/src/intrinsics.rs12
-rw-r--r--library/core/src/num/f128.rs20
-rw-r--r--library/core/src/num/f16.rs20
-rw-r--r--library/core/src/num/f64.rs1
-rw-r--r--library/core/src/ptr/mut_ptr.rs2
-rw-r--r--library/core/src/result.rs12
-rw-r--r--library/core/src/slice/mod.rs16
-rw-r--r--library/core/src/time.rs34
-rw-r--r--library/core/tests/slice.rs4
-rw-r--r--library/std/src/f128.rs24
-rw-r--r--library/std/src/f16.rs24
-rw-r--r--library/std/src/sys/pal/unix/alloc.rs19
m---------library/stdarch0
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs5
-rw-r--r--src/bootstrap/src/core/config/config.rs62
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/doc/rustc/src/linker-plugin-lto.md3
-rw-r--r--src/doc/rustdoc/src/command-line-arguments.md6
-rw-r--r--src/etc/lldb_lookup.py2
-rw-r--r--src/etc/lldb_providers.py3
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs6
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/librustdoc/clean/types.rs14
-rw-r--r--src/librustdoc/config.rs51
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/doctest.rs4
-rw-r--r--src/librustdoc/html/format.rs10
-rw-r--r--src/librustdoc/html/render/mod.rs8
-rw-r--r--src/librustdoc/html/render/print_item.rs14
-rw-r--r--src/librustdoc/json/conversions.rs10
-rw-r--r--src/librustdoc/lib.rs10
-rw-r--r--src/librustdoc/markdown.rs14
-rw-r--r--src/rustdoc-json-types/lib.rs14
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs10
-rw-r--r--src/tools/run-make-support/src/rustc.rs6
-rw-r--r--src/tools/rustfmt/src/items.rs22
-rw-r--r--src/tools/rustfmt/src/types.rs2
-rw-r--r--src/tools/rustfmt/src/utils.rs6
-rw-r--r--src/tools/rustfmt/src/visitor.rs10
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt5
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--src/tools/tidy/src/ui_tests.rs1
-rw-r--r--tests/codegen/float/f128.rs194
-rw-r--r--tests/codegen/float/f16.rs202
-rw-r--r--tests/codegen/intrinsics/aggregate-thin-pointer.rs23
-rw-r--r--tests/debuginfo/empty-string.rs2
-rw-r--r--tests/debuginfo/pretty-slices.rs4
-rw-r--r--tests/debuginfo/strings-and-strs.rs63
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff8
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff8
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir2
-rw-r--r--tests/run-make/box-struct-no-segfault/foo.rs (renamed from tests/run-make/issue-28766/foo.rs)0
-rw-r--r--tests/run-make/box-struct-no-segfault/main.rs (renamed from tests/run-make/issue-28766/main.rs)0
-rw-r--r--tests/run-make/box-struct-no-segfault/rmake.rs13
-rw-r--r--tests/run-make/issue-28766/Makefile5
-rw-r--r--tests/run-make/issue64319/Makefile40
-rw-r--r--tests/run-make/rust-lld-by-default/main.rs5
-rw-r--r--tests/run-make/rust-lld-by-default/rmake.rs43
-rw-r--r--tests/run-make/rustdoc-scrape-examples-invalid-expr/Makefile5
-rw-r--r--tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs6
-rw-r--r--tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs49
-rw-r--r--tests/run-make/rustdoc-scrape-examples-remap/Makefile5
-rw-r--r--tests/run-make/rustdoc-scrape-examples-remap/rmake.rs5
-rw-r--r--tests/run-make/rustdoc-scrape-examples-remap/scrape.rs49
-rw-r--r--tests/run-make/share-generics-export-again/bar.rs (renamed from tests/run-make/issue64319/bar.rs)0
-rw-r--r--tests/run-make/share-generics-export-again/foo.rs (renamed from tests/run-make/issue64319/foo.rs)0
-rw-r--r--tests/run-make/share-generics-export-again/rmake.rs45
-rw-r--r--tests/run-make/static-unwinding/Makefile8
-rw-r--r--tests/run-make/static-unwinding/rmake.rs15
-rw-r--r--tests/run-make/stdin-rustdoc/rmake.rs25
-rw-r--r--tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr9
-rw-r--r--tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs11
-rw-r--r--tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr24
-rw-r--r--tests/ui/for/issue-20605.next.stderr20
-rw-r--r--tests/ui/for/issue-20605.rs3
-rw-r--r--tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs19
-rw-r--r--tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr7
-rw-r--r--tests/ui/intrinsics/safe-intrinsic-mismatch.stderr4
-rw-r--r--tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr2
-rw-r--r--tests/ui/lint/unused/unused-macro-rules-compile-error.rs6
-rw-r--r--tests/ui/lint/unused/unused-macro-rules-compile-error.stderr6
-rw-r--r--tests/ui/lint/unused/unused-macro-rules-decl.rs6
-rw-r--r--tests/ui/lint/unused/unused-macro-rules-decl.stderr6
-rw-r--r--tests/ui/lint/unused/unused-macro-rules.rs6
-rw-r--r--tests/ui/lint/unused/unused-macro-rules.stderr6
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2021.stderr32
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2024.stderr17
-rw-r--r--tests/ui/macros/expr_2021_inline_const.rs23
-rw-r--r--tests/ui/macros/expr_2021_old_edition.rs13
-rw-r--r--tests/ui/macros/expr_2021_old_edition.stderr26
-rw-r--r--tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs11
-rw-r--r--tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr13
-rw-r--r--tests/ui/macros/issue-98790.rs24
-rw-r--r--tests/ui/macros/missing-semi.rs11
-rw-r--r--tests/ui/macros/missing-semi.stderr8
-rw-r--r--tests/ui/macros/println-percent-prefix-num-issue-125002.rs6
-rw-r--r--tests/ui/macros/println-percent-prefix-num-issue-125002.stderr28
-rw-r--r--tests/ui/proc-macro/signature.stderr2
-rw-r--r--tests/ui/traits/impl-method-mismatch.stderr2
-rw-r--r--tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr6
-rw-r--r--tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr6
-rw-r--r--tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr9
-rw-r--r--tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr36
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr12
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr41
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr39
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr25
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs21
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr12
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs21
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr12
-rw-r--r--tests/ui/traits/next-solver/issue-118950-root-region.rs2
-rw-r--r--tests/ui/traits/next-solver/issue-118950-root-region.stderr12
-rw-r--r--tests/ui/traits/next-solver/member-constraints-in-root-universe.rs17
-rw-r--r--tests/ui/traits/next-solver/member-constraints-in-root-universe.stderr8
-rw-r--r--tests/ui/traits/next-solver/object-unsafety.rs3
-rw-r--r--tests/ui/traits/next-solver/object-unsafety.stderr18
-rw-r--r--tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs2
-rw-r--r--tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr9
-rw-r--r--tests/ui/traits/next-solver/overflow/global-cache.stderr9
-rw-r--r--tests/ui/unpretty/auxiliary/data.txt1
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.rs888
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.stdout719
-rw-r--r--tests/ui/unpretty/expanded-interpolation.rs106
-rw-r--r--tests/ui/unpretty/expanded-interpolation.stdout92
-rw-r--r--tests/ui/unpretty/let-else.rs11
-rw-r--r--tests/ui/unpretty/let-else.stdout15
-rw-r--r--tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr2
-rw-r--r--tests/ui/unsafe/unsafe-subtyping.stderr2
-rw-r--r--tests/ui/unsafe/unsafe-trait-impl.stderr2
-rw-r--r--tests/ui/wf/wf-normalization-sized.next.stderr31
-rw-r--r--tests/ui/wf/wf-normalization-sized.rs8
-rw-r--r--triagebot.toml1
340 files changed, 5379 insertions, 2298 deletions
diff --git a/Cargo.lock b/Cargo.lock
index df4e4f32613..186892af21c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4343,6 +4343,7 @@ dependencies = [
  "rustc_hir_pretty",
  "rustc_index",
  "rustc_macros",
+ "rustc_next_trait_solver",
  "rustc_query_system",
  "rustc_serialize",
  "rustc_session",
@@ -4451,7 +4452,13 @@ dependencies = [
 name = "rustc_next_trait_solver"
 version = "0.0.0"
 dependencies = [
+ "derivative",
+ "rustc_ast_ir",
+ "rustc_data_structures",
+ "rustc_macros",
+ "rustc_serialize",
  "rustc_type_ir",
+ "rustc_type_ir_macros",
 ]
 
 [[package]]
@@ -4752,6 +4759,7 @@ name = "rustc_trait_selection"
 version = "0.0.0"
 dependencies = [
  "bitflags 2.5.0",
+ "derivative",
  "itertools 0.12.1",
  "rustc_ast",
  "rustc_ast_ir",
@@ -4767,10 +4775,13 @@ dependencies = [
  "rustc_next_trait_solver",
  "rustc_parse_format",
  "rustc_query_system",
+ "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
  "rustc_transmute",
+ "rustc_type_ir",
+ "rustc_type_ir_macros",
  "smallvec",
  "tracing",
 ]
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index c57be5d1106..a95ef4c460f 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -2,7 +2,6 @@ use std::borrow::{Borrow, Cow};
 use std::cmp;
 use std::fmt::{self, Write};
 use std::iter;
-use std::num::NonZero;
 use std::ops::Bound;
 use std::ops::Deref;
 
@@ -11,8 +10,8 @@ use tracing::debug;
 
 use crate::{
     Abi, AbiAndPrefAlign, Align, FieldsShape, IndexSlice, IndexVec, Integer, LayoutS, Niche,
-    Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout, Variants,
-    WrappingRange,
+    NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout,
+    Variants, WrappingRange,
 };
 
 // A variant is absent if it's uninhabited and only has ZST fields.
@@ -328,7 +327,7 @@ pub trait LayoutCalculator {
 
         Some(LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
-            fields: FieldsShape::Union(NonZero::new(only_variant.len())?),
+            fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?),
             abi,
             largest_niche: None,
             align,
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 9f2788c87c3..53aa8ad7cca 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -4,7 +4,7 @@
 #![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
 
 use std::fmt;
-use std::num::{NonZero, ParseIntError};
+use std::num::{NonZeroUsize, ParseIntError};
 use std::ops::{Add, AddAssign, Mul, RangeInclusive, Sub};
 use std::str::FromStr;
 
@@ -1175,7 +1175,7 @@ pub enum FieldsShape<FieldIdx: Idx> {
     Primitive,
 
     /// All fields start at no offset. The `usize` is the field count.
-    Union(NonZero<usize>),
+    Union(NonZeroUsize),
 
     /// Array/vector-like placement, with all fields of identical types.
     Array { stride: Size, count: u64 },
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 14e04774788..5d37bbd689f 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2105,7 +2105,7 @@ impl Ty {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct BareFnTy {
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub ext: Extern,
     pub generic_params: ThinVec<GenericParam>,
     pub decl: P<FnDecl>,
@@ -2484,11 +2484,15 @@ pub enum IsAuto {
     No,
 }
 
+/// Safety of items.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
-pub enum Unsafe {
-    Yes(Span),
-    No,
+pub enum Safety {
+    /// `unsafe` an item is explicitly marked as `unsafe`.
+    Unsafe(Span),
+    /// Default means no value was provided, it will take a default value given the context in
+    /// which is used.
+    Default,
 }
 
 /// Describes what kind of coroutine markers, if any, a function has.
@@ -2692,7 +2696,7 @@ pub struct ModSpans {
 pub struct ForeignMod {
     /// `unsafe` keyword accepted syntactically for macro DSLs, but not
     /// semantically by Rust.
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub abi: Option<StrLit>,
     pub items: ThinVec<P<ForeignItem>>,
 }
@@ -3011,8 +3015,8 @@ impl Extern {
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
-    /// The `unsafe` keyword, if any
-    pub unsafety: Unsafe,
+    /// Whether this is `unsafe`, or has a default safety
+    pub safety: Safety,
     /// Whether this is `async`, `gen`, or nothing.
     pub coroutine_kind: Option<CoroutineKind>,
     /// The `const` keyword, if any
@@ -3024,8 +3028,8 @@ pub struct FnHeader {
 impl FnHeader {
     /// Does this function header have any qualifiers or is it empty?
     pub fn has_qualifiers(&self) -> bool {
-        let Self { unsafety, coroutine_kind, constness, ext } = self;
-        matches!(unsafety, Unsafe::Yes(_))
+        let Self { safety, coroutine_kind, constness, ext } = self;
+        matches!(safety, Safety::Unsafe(_))
             || coroutine_kind.is_some()
             || matches!(constness, Const::Yes(_))
             || !matches!(ext, Extern::None)
@@ -3035,7 +3039,7 @@ impl FnHeader {
 impl Default for FnHeader {
     fn default() -> FnHeader {
         FnHeader {
-            unsafety: Unsafe::No,
+            safety: Safety::Default,
             coroutine_kind: None,
             constness: Const::No,
             ext: Extern::None,
@@ -3045,7 +3049,7 @@ impl Default for FnHeader {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Trait {
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub is_auto: IsAuto,
     pub generics: Generics,
     pub bounds: GenericBounds,
@@ -3101,7 +3105,7 @@ pub struct TyAlias {
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Impl {
     pub defaultness: Defaultness,
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub generics: Generics,
     pub constness: Const,
     pub polarity: ImplPolarity,
@@ -3209,7 +3213,7 @@ pub enum ItemKind {
     /// E.g., `mod foo;` or `mod foo { .. }`.
     /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not
     /// semantically by Rust.
-    Mod(Unsafe, ModKind),
+    Mod(Safety, ModKind),
     /// An external module (`extern`).
     ///
     /// E.g., `extern {}` or `extern "C" {}`.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 1cfb8972a62..566b20c490e 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -499,8 +499,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
             vis.visit_mt(mt);
         }
         TyKind::BareFn(bft) => {
-            let BareFnTy { unsafety, ext: _, generic_params, decl, decl_span } = bft.deref_mut();
-            visit_unsafety(unsafety, vis);
+            let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = bft.deref_mut();
+            visit_safety(safety, vis);
             generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
             vis.visit_fn_decl(decl);
             vis.visit_span(decl_span);
@@ -543,8 +543,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
 }
 
 fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
-    let ForeignMod { unsafety, abi: _, items } = foreign_mod;
-    visit_unsafety(unsafety, vis);
+    let ForeignMod { safety, abi: _, items } = foreign_mod;
+    visit_safety(safety, vis);
     items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
 }
 
@@ -859,10 +859,10 @@ fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T)
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) {
-    match unsafety {
-        Unsafe::Yes(span) => vis.visit_span(span),
-        Unsafe::No => {}
+fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) {
+    match safety {
+        Safety::Unsafe(span) => vis.visit_span(span),
+        Safety::Default => {}
     }
 }
 
@@ -1092,8 +1092,8 @@ impl NoopVisitItemKind for ItemKind {
                 vis.visit_generics(generics);
                 visit_opt(body, |body| vis.visit_block(body));
             }
-            ItemKind::Mod(unsafety, mod_kind) => {
-                visit_unsafety(unsafety, vis);
+            ItemKind::Mod(safety, mod_kind) => {
+                visit_safety(safety, vis);
                 match mod_kind {
                     ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
                         vis.visit_span(inner_span);
@@ -1130,7 +1130,7 @@ impl NoopVisitItemKind for ItemKind {
             }
             ItemKind::Impl(box Impl {
                 defaultness,
-                unsafety,
+                safety,
                 generics,
                 constness,
                 polarity,
@@ -1139,7 +1139,7 @@ impl NoopVisitItemKind for ItemKind {
                 items,
             }) => {
                 visit_defaultness(defaultness, vis);
-                visit_unsafety(unsafety, vis);
+                visit_safety(safety, vis);
                 vis.visit_generics(generics);
                 visit_constness(constness, vis);
                 visit_polarity(polarity, vis);
@@ -1147,8 +1147,8 @@ impl NoopVisitItemKind for ItemKind {
                 vis.visit_ty(self_ty);
                 items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
             }
-            ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => {
-                visit_unsafety(unsafety, vis);
+            ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => {
+                visit_safety(safety, vis);
                 vis.visit_generics(generics);
                 visit_bounds(bounds, vis);
                 items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
@@ -1254,10 +1254,10 @@ fn visit_const_item<T: MutVisitor>(
 }
 
 fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
-    let FnHeader { unsafety, coroutine_kind, constness, ext: _ } = header;
+    let FnHeader { safety, coroutine_kind, constness, ext: _ } = header;
     visit_constness(constness, vis);
     coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
-    visit_unsafety(unsafety, vis);
+    visit_safety(safety, vis);
 }
 
 pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index d00352ea2e1..099a6096d0b 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -881,6 +881,8 @@ pub enum NonterminalKind {
     },
     PatWithOr,
     Expr,
+    /// Matches an expression using the rules from edition 2021 and earlier.
+    Expr2021,
     Ty,
     Ident,
     Lifetime,
@@ -910,6 +912,7 @@ impl NonterminalKind {
             },
             sym::pat_param => NonterminalKind::PatParam { inferred: false },
             sym::expr => NonterminalKind::Expr,
+            sym::expr_2021 if edition().at_least_rust_2021() => NonterminalKind::Expr2021,
             sym::ty => NonterminalKind::Ty,
             sym::ident => NonterminalKind::Ident,
             sym::lifetime => NonterminalKind::Lifetime,
@@ -929,6 +932,7 @@ impl NonterminalKind {
             NonterminalKind::PatParam { inferred: false } => sym::pat_param,
             NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
             NonterminalKind::Expr => sym::expr,
+            NonterminalKind::Expr2021 => sym::expr_2021,
             NonterminalKind::Ty => sym::ty,
             NonterminalKind::Ident => sym::ident,
             NonterminalKind::Lifetime => sym::lifetime,
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 7794edc3505..93de42b55cc 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -366,7 +366,7 @@ impl WalkItemKind for ItemKind {
             }
             ItemKind::Impl(box Impl {
                 defaultness: _,
-                unsafety: _,
+                safety: _,
                 generics,
                 constness: _,
                 polarity: _,
@@ -384,7 +384,7 @@ impl WalkItemKind for ItemKind {
                 try_visit!(visitor.visit_generics(generics));
                 try_visit!(visitor.visit_variant_data(struct_definition));
             }
-            ItemKind::Trait(box Trait { unsafety: _, is_auto: _, generics, bounds, items }) => {
+            ItemKind::Trait(box Trait { safety: _, is_auto: _, generics, bounds, items }) => {
                 try_visit!(visitor.visit_generics(generics));
                 walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits);
                 walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index a1e5c275c18..27f8a6eae02 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -188,7 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 Asyncness::No => hir::IsAsync::NotAsync,
             };
             hir::FnHeader {
-                unsafety: sig.unsafety,
+                safety: sig.safety,
                 constness: self.tcx.constness(sig_id),
                 asyncness,
                 abi: sig.abi,
@@ -341,7 +341,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn generate_header_error(&self) -> hir::FnHeader {
         hir::FnHeader {
-            unsafety: hir::Unsafety::Normal,
+            safety: hir::Safety::Safe,
             constness: hir::Constness::NotConst,
             asyncness: hir::IsAsync::NotAsync,
             abi: abi::Abi::Rust,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1255c1bba08..a15449409df 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -323,7 +323,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 hir::ItemKind::Union(vdata, generics)
             }
             ItemKind::Impl(box Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 constness,
@@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
                 };
                 hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
-                    unsafety: self.lower_unsafety(*unsafety),
+                    safety: self.lower_safety(*safety),
                     polarity,
                     defaultness,
                     defaultness_span,
@@ -398,14 +398,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     items: new_impl_items,
                 }))
             }
-            ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => {
+            ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
                 // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible
                 let constness = attrs
                     .unwrap_or(&[])
                     .iter()
                     .find(|x| x.has_name(sym::const_trait))
                     .map_or(Const::No, |x| Const::Yes(x.span));
-                let (generics, (unsafety, items, bounds)) = self.lower_generics(
+                let (generics, (safety, items, bounds)) = self.lower_generics(
                     generics,
                     constness,
                     id,
@@ -418,11 +418,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         let items = this.arena.alloc_from_iter(
                             items.iter().map(|item| this.lower_trait_item_ref(item)),
                         );
-                        let unsafety = this.lower_unsafety(*unsafety);
-                        (unsafety, items, bounds)
+                        let safety = this.lower_safety(*safety);
+                        (safety, items, bounds)
                     },
                 );
-                hir::ItemKind::Trait(*is_auto, unsafety, generics, bounds, items)
+                hir::ItemKind::Trait(*is_auto, safety, generics, bounds, items)
             }
             ItemKind::TraitAlias(generics, bounds) => {
                 let (generics, bounds) = self.lower_generics(
@@ -1360,7 +1360,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             hir::IsAsync::NotAsync
         };
         hir::FnHeader {
-            unsafety: self.lower_unsafety(h.unsafety),
+            safety: self.lower_safety(h.safety),
             asyncness: asyncness,
             constness: self.lower_constness(h.constness),
             abi: self.lower_extern(h.ext),
@@ -1410,10 +1410,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    pub(super) fn lower_unsafety(&mut self, u: Unsafe) -> hir::Unsafety {
-        match u {
-            Unsafe::Yes(_) => hir::Unsafety::Unsafe,
-            Unsafe::No => hir::Unsafety::Normal,
+    pub(super) fn lower_safety(&mut self, s: Safety) -> hir::Safety {
+        match s {
+            Safety::Unsafe(_) => hir::Safety::Unsafe,
+            Safety::Default => hir::Safety::Safe,
         }
     }
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index c23da8aa01e..a9af5ad7459 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1324,7 +1324,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
                 hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
                     generic_params,
-                    unsafety: self.lower_unsafety(f.unsafety),
+                    safety: self.lower_safety(f.safety),
                     abi: self.lower_extern(f.ext),
                     decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
                     param_names: self.lower_fn_params_to_names(&f.decl),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 172e97e7271..9d07683f8d6 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -521,7 +521,7 @@ impl<'a> AstValidator<'a> {
     fn check_foreign_fn_headerless(
         &self,
         // Deconstruct to ensure exhaustiveness
-        FnHeader { unsafety, coroutine_kind, constness, ext }: FnHeader,
+        FnHeader { safety, coroutine_kind, constness, ext }: FnHeader,
     ) {
         let report_err = |span| {
             self.dcx().emit_err(errors::FnQualifierInExtern {
@@ -529,9 +529,9 @@ impl<'a> AstValidator<'a> {
                 block: self.current_extern_span(),
             });
         };
-        match unsafety {
-            Unsafe::Yes(span) => report_err(span),
-            Unsafe::No => (),
+        match safety {
+            Safety::Unsafe(span) => report_err(span),
+            Safety::Default => (),
         }
         match coroutine_kind {
             Some(knd) => report_err(knd.span()),
@@ -592,7 +592,7 @@ impl<'a> AstValidator<'a> {
             (Some(FnCtxt::Free), Some(header)) => match header.ext {
                 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
                 | Extern::Implicit(_)
-                    if matches!(header.unsafety, Unsafe::Yes(_)) =>
+                    if matches!(header.safety, Safety::Unsafe(_)) =>
                 {
                     return;
                 }
@@ -891,7 +891,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         match &item.kind {
             ItemKind::Impl(box Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness: _,
                 constness,
@@ -910,7 +910,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         // which isn't allowed. Not a problem for this obscure, obsolete syntax.
                         this.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });
                     }
-                    if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
+                    if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity)
                     {
                         this.dcx().emit_err(errors::UnsafeNegativeImpl {
                             span: sp.to(t.path.span),
@@ -933,7 +933,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 return; // Avoid visiting again.
             }
             ItemKind::Impl(box Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 constness,
@@ -956,7 +956,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         &item.vis,
                         errors::VisibilityNotPermittedNote::IndividualImplItems,
                     );
-                    if let &Unsafe::Yes(span) = unsafety {
+                    if let &Safety::Unsafe(span) = safety {
                         this.dcx().emit_err(errors::InherentImplCannotUnsafe {
                             span: self_ty.span,
                             annotation_span: span,
@@ -1020,13 +1020,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
             }
-            ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
+            ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => {
                 let old_item = mem::replace(&mut self.extern_mod, Some(item));
                 self.visibility_not_permitted(
                     &item.vis,
                     errors::VisibilityNotPermittedNote::IndividualForeignItems,
                 );
-                if let &Unsafe::Yes(span) = unsafety {
+                if let &Safety::Unsafe(span) = safety {
                     self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
                 }
                 if abi.is_none() {
@@ -1078,8 +1078,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again
             }
-            ItemKind::Mod(unsafety, mod_kind) => {
-                if let &Unsafe::Yes(span) = unsafety {
+            ItemKind::Mod(safety, mod_kind) => {
+                if let &Safety::Unsafe(span) = safety {
                     self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index defb666e2b6..545b98a9135 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -524,7 +524,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         }
     }
 
-    fn peek_comment<'b>(&'b self) -> Option<&'b Comment> where 'a: 'b {
+    fn peek_comment<'b>(&'b self) -> Option<&'b Comment>
+    where
+        'a: 'b,
+    {
         self.comments().and_then(|c| c.peek())
     }
 
@@ -1150,7 +1153,7 @@ impl<'a> State<'a> {
                 self.pclose();
             }
             ast::TyKind::BareFn(f) => {
-                self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
+                self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
             }
             ast::TyKind::Path(None, path) => {
                 self.print_path(path, false, 0);
@@ -1908,7 +1911,7 @@ impl<'a> State<'a> {
     fn print_ty_fn(
         &mut self,
         ext: ast::Extern,
-        unsafety: ast::Unsafe,
+        safety: ast::Safety,
         decl: &ast::FnDecl,
         name: Option<Ident>,
         generic_params: &[ast::GenericParam],
@@ -1924,7 +1927,7 @@ impl<'a> State<'a> {
             },
             span: DUMMY_SP,
         };
-        let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
+        let header = ast::FnHeader { safety, ext, ..ast::FnHeader::default() };
         self.print_fn(decl, header, name, &generics);
         self.end();
     }
@@ -1932,7 +1935,7 @@ impl<'a> State<'a> {
     fn print_fn_header_info(&mut self, header: ast::FnHeader) {
         self.print_constness(header.constness);
         header.coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind));
-        self.print_unsafety(header.unsafety);
+        self.print_safety(header.safety);
 
         match header.ext {
             ast::Extern::None => {}
@@ -1949,10 +1952,10 @@ impl<'a> State<'a> {
         self.word("fn")
     }
 
-    fn print_unsafety(&mut self, s: ast::Unsafe) {
+    fn print_safety(&mut self, s: ast::Safety) {
         match s {
-            ast::Unsafe::No => {}
-            ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
+            ast::Safety::Default => {}
+            ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"),
         }
     }
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 16c3ee948a4..59d9b0c1a8e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -198,10 +198,10 @@ impl<'a> State<'a> {
                     &item.attrs,
                 );
             }
-            ast::ItemKind::Mod(unsafety, mod_kind) => {
+            ast::ItemKind::Mod(safety, mod_kind) => {
                 self.head(Self::to_string(|s| {
                     s.print_visibility(&item.vis);
-                    s.print_unsafety(*unsafety);
+                    s.print_safety(*safety);
                     s.word("mod");
                 }));
                 self.print_ident(item.ident);
@@ -226,7 +226,7 @@ impl<'a> State<'a> {
             }
             ast::ItemKind::ForeignMod(nmod) => {
                 self.head(Self::to_string(|s| {
-                    s.print_unsafety(nmod.unsafety);
+                    s.print_safety(nmod.safety);
                     s.word("extern");
                 }));
                 if let Some(abi) = nmod.abi {
@@ -275,7 +275,7 @@ impl<'a> State<'a> {
                 self.print_struct(struct_def, generics, item.ident, item.span, true);
             }
             ast::ItemKind::Impl(box ast::Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 constness,
@@ -287,7 +287,7 @@ impl<'a> State<'a> {
                 self.head("");
                 self.print_visibility(&item.vis);
                 self.print_defaultness(*defaultness);
-                self.print_unsafety(*unsafety);
+                self.print_safety(*safety);
                 self.word("impl");
 
                 if generics.params.is_empty() {
@@ -323,7 +323,7 @@ impl<'a> State<'a> {
             }
             ast::ItemKind::Trait(box ast::Trait {
                 is_auto,
-                unsafety,
+                safety,
                 generics,
                 bounds,
                 items,
@@ -331,7 +331,7 @@ impl<'a> State<'a> {
             }) => {
                 self.head("");
                 self.print_visibility(&item.vis);
-                self.print_unsafety(*unsafety);
+                self.print_safety(*safety);
                 self.print_is_auto(*is_auto);
                 self.word_nbsp("trait");
                 self.print_ident(item.ident);
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index ccc45e2829a..15050c87b39 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -24,8 +24,8 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
-    self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
-    TypeSuperVisitable, TypeVisitor,
+    self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt, TypeSuperVisitable,
+    TypeVisitor, Upcast,
 };
 use rustc_middle::util::CallKind;
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
@@ -1915,7 +1915,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             self.infcx.err_ctxt().suggest_derive(
                 &obligation,
                 err,
-                trait_ref.to_predicate(self.infcx.tcx),
+                trait_ref.upcast(self.infcx.tcx),
             );
         }
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index c9a09c19ce6..35017b9e6b5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -9,7 +9,7 @@ use rustc_hir::{self as hir, BindingMode, ByRef, Node};
 use rustc_infer::traits;
 use rustc_middle::bug;
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, Upcast};
 use rustc_middle::{
     hir::place::PlaceBase,
     mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
@@ -1255,7 +1255,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 self.infcx.err_ctxt().suggest_derive(
                                     &obligation,
                                     err,
-                                    trait_ref.to_predicate(self.infcx.tcx),
+                                    trait_ref.upcast(self.infcx.tcx),
                                 );
                             }
                             Some(errors) => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index d8d582b0ad1..8112fb7b89c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1098,7 +1098,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 liberated_sig.inputs().iter().copied(),
                 peeled_ty,
                 liberated_sig.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 rustc_target::spec::abi::Abi::Rust,
             )),
         );
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 49d3f7381d9..2dc2568cd47 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -4,7 +4,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::canonical::Canonical;
 use rustc_middle::bug;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
@@ -115,7 +115,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
     pub(super) fn prove_predicates(
         &mut self,
-        predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>,
+        predicates: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + std::fmt::Debug>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
@@ -127,12 +127,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     #[instrument(skip(self), level = "debug")]
     pub(super) fn prove_predicate(
         &mut self,
-        predicate: impl ToPredicate<'tcx> + std::fmt::Debug,
+        predicate: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + std::fmt::Debug,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
         let param_env = self.param_env;
-        let predicate = predicate.to_predicate(self.tcx());
+        let predicate = predicate.upcast(self.tcx());
         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             locations,
             category,
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 4e45dc42aa7..741ec05dc9a 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -98,7 +98,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 user_provided_sig.inputs().iter().copied(),
                 output_ty,
                 user_provided_sig.c_variadic,
-                user_provided_sig.unsafety,
+                user_provided_sig.safety,
                 user_provided_sig.abi,
             );
         }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 2740e9689c5..6cf9ac45aa3 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2007,13 +2007,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
 
-                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(unsafety)) => {
+                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(safety)) => {
                         let sig = match op.ty(body, tcx).kind() {
                             ty::Closure(_, args) => args.as_closure().sig(),
                             _ => bug!(),
                         };
                         let ty_fn_ptr_from =
-                            Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *unsafety));
+                            Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *safety));
 
                         if let Err(terr) = self.eq_types(
                             *ty,
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 493c41e59e3..cbd8a4125cd 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -546,7 +546,10 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx
         self.type_checker.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.register_obligations(
             obligations
                 .into_iter()
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 064cf7d7f0f..4721e74b955 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -3,7 +3,7 @@ use crate::util::check_builtin_macro_attribute;
 
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
-use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Safety, Stmt, TyKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -78,7 +78,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
     let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
     let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
     let decl = cx.fn_decl(params, never);
-    let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
+    let header = FnHeader { safety: Safety::Unsafe(span), ..FnHeader::default() };
     let sig = FnSig { decl, header, span: span };
 
     let body = Some(cx.block_expr(call));
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 52c1ba1757b..46949f731aa 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -788,7 +788,7 @@ impl<'a> TraitDef<'a> {
             Ident::empty(),
             attrs,
             ast::ItemKind::Impl(Box::new(ast::Impl {
-                unsafety: ast::Unsafe::No,
+                safety: ast::Safety::Default,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
                 constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 307e582d65e..bc2c6def68a 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -263,13 +263,13 @@ pub(crate) mod printf {
     }
 
     impl Num {
-        fn from_str(s: &str, arg: Option<&str>) -> Self {
+        fn from_str(s: &str, arg: Option<&str>) -> Option<Self> {
             if let Some(arg) = arg {
-                Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`")))
+                arg.parse().ok().map(|arg| Num::Arg(arg))
             } else if s == "*" {
-                Num::Next
+                Some(Num::Next)
             } else {
-                Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`")))
+                s.parse().ok().map(|num| Num::Num(num))
             }
         }
 
@@ -421,7 +421,10 @@ pub(crate) mod printf {
                             state = Prec;
                             parameter = None;
                             flags = "";
-                            width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                            width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                            if width.is_none() {
+                                return fallback();
+                            }
                             move_to!(end);
                         }
                         // It's invalid, is what it is.
@@ -452,7 +455,10 @@ pub(crate) mod printf {
                 '1'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Prec;
-                    width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                    if width.is_none() {
+                        return fallback();
+                    }
                     move_to!(end);
                 }
                 _ => {
@@ -468,7 +474,7 @@ pub(crate) mod printf {
             match end.next_cp() {
                 Some(('$', end2)) => {
                     state = Prec;
-                    width = Some(Num::from_str("", Some(at.slice_between(end).unwrap())));
+                    width = Num::from_str("", at.slice_between(end));
                     move_to!(end2);
                 }
                 _ => {
@@ -500,7 +506,7 @@ pub(crate) mod printf {
                     match end.next_cp() {
                         Some(('$', end2)) => {
                             state = Length;
-                            precision = Some(Num::from_str("*", next.slice_between(end)));
+                            precision = Num::from_str("*", next.slice_between(end));
                             move_to!(end2);
                         }
                         _ => {
@@ -513,7 +519,7 @@ pub(crate) mod printf {
                 '0'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Length;
-                    precision = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    precision = at.slice_between(end).and_then(|num| Num::from_str(num, None));
                     move_to!(end);
                 }
                 _ => return fallback(),
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index a1630ad1379..b44ff979303 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -6,7 +6,7 @@ use rustc_ast::expand::allocator::{
 };
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Mutability, Safety, Stmt, Ty, TyKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
@@ -73,7 +73,7 @@ impl AllocFnFactory<'_, '_> {
         let result = self.call_allocator(method.name, args);
         let output_ty = self.ret_ty(&method.output);
         let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
-        let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
+        let header = FnHeader { safety: Safety::Unsafe(self.span), ..FnHeader::default() };
         let sig = FnSig { decl, header, span: self.span };
         let body = Some(self.cx.block_expr(result));
         let kind = ItemKind::Fn(Box::new(Fn {
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 1e4bf4611cf..8f96070d149 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -549,7 +549,7 @@ fn check_test_signature(
     let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
     let dcx = cx.dcx();
 
-    if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
+    if let ast::Safety::Unsafe(span) = f.sig.header.safety {
         return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index b6d6d211e65..4146137c226 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -872,7 +872,7 @@ pub(crate) fn assert_assignable<'tcx>(
             let FnSig {
                 inputs_and_output: types_from,
                 c_variadic: c_variadic_from,
-                unsafety: unsafety_from,
+                safety: unsafety_from,
                 abi: abi_from,
             } = from_sig;
             let to_sig = fx
@@ -881,7 +881,7 @@ pub(crate) fn assert_assignable<'tcx>(
             let FnSig {
                 inputs_and_output: types_to,
                 c_variadic: c_variadic_to,
-                unsafety: unsafety_to,
+                safety: unsafety_to,
                 abi: abi_to,
             } = to_sig;
             let mut types_from = types_from.iter();
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 451e5258ebd..43f12b514af 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -670,11 +670,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                 let step3 = self.or(left, right);
 
                 // Fourth step.
-                if width == 8 {
-                    step3
-                } else {
-                    self.gcc_bswap(step3, width)
-                }
+                if width == 8 { step3 } else { self.gcc_bswap(step3, width) }
             }
             128 => {
                 // TODO(antoyo): find a more efficient implementation?
@@ -1225,7 +1221,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(
             iter::once(i8p),
             tcx.types.unit,
             false,
-            rustc_hir::Unsafety::Unsafe,
+            rustc_hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -1236,7 +1232,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(
             [i8p, i8p].iter().cloned(),
             tcx.types.unit,
             false,
-            rustc_hir::Unsafety::Unsafe,
+            rustc_hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -1245,7 +1241,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(
         [try_fn_ty, i8p, catch_fn_ty],
         tcx.types.i32,
         false,
-        rustc_hir::Unsafety::Unsafe,
+        rustc_hir::Safety::Unsafe,
         Abi::Rust,
     ));
     let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index b0b867701a4..c0a1208a8c7 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -990,7 +990,7 @@ fn get_rust_try_fn<'ll, 'tcx>(
             [i8p],
             tcx.types.unit,
             false,
-            hir::Unsafety::Unsafe,
+            hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -1001,7 +1001,7 @@ fn get_rust_try_fn<'ll, 'tcx>(
             [i8p, i8p],
             tcx.types.unit,
             false,
-            hir::Unsafety::Unsafe,
+            hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -1010,7 +1010,7 @@ fn get_rust_try_fn<'ll, 'tcx>(
         [try_fn_ty, i8p, catch_fn_ty],
         tcx.types.i32,
         false,
-        hir::Unsafety::Unsafe,
+        hir::Safety::Unsafe,
         Abi::Rust,
     ));
     let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index c28b0d644e6..9bf055b1739 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -276,7 +276,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             sym::target_feature => {
                 if !tcx.is_closure_like(did.to_def_id())
                     && let Some(fn_sig) = fn_sig()
-                    && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal
+                    && fn_sig.skip_binder().safety() == hir::Safety::Safe
                 {
                     if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
                         // The `#[target_feature]` attribute is allowed on
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index e9c7606dc5a..07473ee476b 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -365,7 +365,7 @@ fn push_debuginfo_type_name<'tcx>(
                 }
                 output.push_str(" (*)(");
             } else {
-                output.push_str(sig.unsafety.prefix_str());
+                output.push_str(sig.safety.prefix_str());
 
                 if sig.abi != rustc_target::spec::abi::Abi::Rust {
                     output.push_str("extern \"");
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 936ed41a294..ff176a79675 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -121,7 +121,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.write_operand_repeatedly(cg_elem, count, dest);
             }
 
-            mir::Rvalue::Aggregate(ref kind, ref operands) => {
+            // This implementation does field projection, so never use it for `RawPtr`,
+            // which will always be fine with the `codegen_rvalue_operand` path below.
+            mir::Rvalue::Aggregate(ref kind, ref operands)
+                if !matches!(**kind, mir::AggregateKind::RawPtr(..)) =>
+            {
                 let (variant_index, variant_dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
                         let variant_dest = dest.project_downcast(bx, variant_index);
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index fdeccb90700..9fd6eb8edab 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -247,7 +247,10 @@ pub trait BuilderMethods<'a, 'tcx>:
         } else {
             (in_ty, dest_ty)
         };
-        assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double));
+        assert!(matches!(
+            self.cx().type_kind(float_ty),
+            TypeKind::Half | TypeKind::Float | TypeKind::Double | TypeKind::FP128
+        ));
         assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer);
 
         if let Some(false) = self.cx().sess().opts.unstable_opts.saturating_float_casts {
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index ddad6683afb..8c66888d100 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -81,8 +81,8 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
                 if cfg!(debug_assertions) && stab.promotable {
                     let sig = tcx.fn_sig(def_id);
                     assert_eq!(
-                        sig.skip_binder().unsafety(),
-                        hir::Unsafety::Normal,
+                        sig.skip_binder().safety(),
+                        hir::Safety::Safe,
                         "don't mark const unsafe fns as promotable",
                         // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                     );
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index d9add1c9b3b..4bf7dccab92 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -112,6 +112,12 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst
     }
 }
 
+impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        format!("{self:?}").into_diag_arg()
+    }
+}
+
 into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
 
 impl IntoDiagArg for bool {
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 7ae988a5be6..530b37aadb1 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -10,6 +10,11 @@ expand_attribute_meta_item =
 expand_attribute_single_word =
     attribute must only be a single word
 
+expand_attributes_on_expressions_experimental =
+    attributes on expressions are experimental
+    .help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//`
+    .help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
+
 expand_attributes_wrong_form =
     attribute must be of form: `attributes(foo, bar)`
 
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 67a5a9128cc..35f0d8abffc 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -382,7 +382,6 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     #[instrument(level = "trace", skip(self))]
     pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
         if self.features.is_some_and(|features| !features.stmt_expr_attributes)
@@ -392,11 +391,15 @@ impl<'a> StripUnconfigured<'a> {
                 &self.sess,
                 sym::stmt_expr_attributes,
                 attr.span,
-                "attributes on expressions are experimental",
+                crate::fluent_generated::expand_attributes_on_expressions_experimental,
             );
 
             if attr.is_doc_comment() {
-                err.help("`///` is for documentation comments. For a plain comment, use `//`.");
+                err.help(if attr.style == AttrStyle::Outer {
+                    crate::fluent_generated::expand_help_outer_doc
+                } else {
+                    crate::fluent_generated::expand_help_inner_doc
+                });
             }
 
             err.emit();
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 3fee39dd085..442fd654b6a 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -55,7 +55,7 @@ pub(super) fn failed_to_match_macro<'cx>(
 
     let span = token.span.substitute_dummy(sp);
 
-    let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token));
+    let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token, None));
     err.span_label(span, label);
     if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
         err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
@@ -200,9 +200,17 @@ impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
 }
 
 /// Currently used by macro_rules! compilation to extract a little information from the `Failure` case.
-pub struct FailureForwarder;
+pub struct FailureForwarder<'matcher> {
+    expected_token: Option<&'matcher Token>,
+}
+
+impl<'matcher> FailureForwarder<'matcher> {
+    pub fn new() -> Self {
+        Self { expected_token: None }
+    }
+}
 
-impl<'matcher> Tracker<'matcher> for FailureForwarder {
+impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> {
     type Failure = (Token, usize, &'static str);
 
     fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
@@ -212,6 +220,14 @@ impl<'matcher> Tracker<'matcher> for FailureForwarder {
     fn description() -> &'static str {
         "failure-forwarder"
     }
+
+    fn set_expected_token(&mut self, tok: &'matcher Token) {
+        self.expected_token = Some(tok);
+    }
+
+    fn get_expected_token(&self) -> Option<&'matcher Token> {
+        self.expected_token
+    }
 }
 
 pub(super) fn emit_frag_parse_err(
@@ -320,9 +336,19 @@ pub(super) fn annotate_doc_comment(dcx: &DiagCtxt, err: &mut Diag<'_>, sm: &Sour
 
 /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
 /// other tokens, this is "unexpected token...".
-pub(super) fn parse_failure_msg(tok: &Token) -> Cow<'static, str> {
-    match tok.kind {
-        token::Eof => Cow::from("unexpected end of macro invocation"),
-        _ => Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))),
+pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> {
+    if let Some(expected_token) = expected_token {
+        Cow::from(format!(
+            "expected `{}`, found `{}`",
+            pprust::token_to_string(expected_token),
+            pprust::token_to_string(tok),
+        ))
+    } else {
+        match tok.kind {
+            token::Eof => Cow::from("unexpected end of macro invocation"),
+            _ => {
+                Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok)))
+            }
+        }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 27cf6fee702..2fbd09fd9ae 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -541,6 +541,8 @@ impl TtParser {
                         // The separator matches the current token. Advance past it.
                         mp.idx += 1;
                         self.next_mps.push(mp);
+                    } else {
+                        track.set_expected_token(separator);
                     }
                 }
                 &MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => {
@@ -632,6 +634,7 @@ impl TtParser {
                 parser.approx_token_stream_pos(),
                 track,
             );
+
             if let Some(res) = res {
                 return res;
             }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 470bde232d7..8f18055f838 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -167,6 +167,11 @@ pub(super) trait Tracker<'matcher> {
     fn recovery() -> Recovery {
         Recovery::Forbidden
     }
+
+    fn set_expected_token(&mut self, _tok: &'matcher Token) {}
+    fn get_expected_token(&self) -> Option<&'matcher Token> {
+        None
+    }
 }
 
 /// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to
@@ -447,16 +452,14 @@ pub fn compile_declarative_macro(
                 // For this we need to reclone the macro body as the previous parser consumed it.
                 let retry_parser = create_parser();
 
-                let parse_result = tt_parser.parse_tt(
-                    &mut Cow::Owned(retry_parser),
-                    &argument_gram,
-                    &mut diagnostics::FailureForwarder,
-                );
+                let mut track = diagnostics::FailureForwarder::new();
+                let parse_result =
+                    tt_parser.parse_tt(&mut Cow::Owned(retry_parser), &argument_gram, &mut track);
                 let Failure((token, _, msg)) = parse_result else {
                     unreachable!("matcher returned something other than Failure after retry");
                 };
 
-                let s = parse_failure_msg(&token);
+                let s = parse_failure_msg(&token, track.get_expected_token());
                 let sp = token.span.substitute_dummy(def.span);
                 let mut err = sess.dcx().struct_span_err(sp, s);
                 err.span_label(sp, msg);
@@ -1290,7 +1293,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                 // maintain
                 IsInFollow::Yes
             }
-            NonterminalKind::Stmt | NonterminalKind::Expr => {
+            NonterminalKind::Stmt | NonterminalKind::Expr | NonterminalKind::Expr2021 => {
                 const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
                 match tok {
                     TokenTree::Token(token) => match token.kind {
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 2e5596f51c3..d3ea48e2e2a 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -16,6 +16,10 @@ use rustc_span::Span;
 const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
                                         `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
                                         `literal`, `path`, `meta`, `tt`, `item` and `vis`";
+const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \
+                                             `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \
+                                             `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
+                                             `item` and `vis`";
 
 /// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
 /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
@@ -63,35 +67,60 @@ pub(super) fn parse(
                             Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
                                 Some((fragment, _)) => {
                                     let span = token.span.with_lo(start_sp.lo());
-
+                                    let edition = || {
+                                        // FIXME(#85708) - once we properly decode a foreign
+                                        // crate's `SyntaxContext::root`, then we can replace
+                                        // this with just `span.edition()`. A
+                                        // `SyntaxContext::root()` from the current crate will
+                                        // have the edition of the current crate, and a
+                                        // `SyntaxContext::root()` from a foreign crate will
+                                        // have the edition of that crate (which we manually
+                                        // retrieve via the `edition` parameter).
+                                        if !span.from_expansion() {
+                                            edition
+                                        } else {
+                                            span.edition()
+                                        }
+                                    };
                                     let kind =
-                                        token::NonterminalKind::from_symbol(fragment.name, || {
-                                            // FIXME(#85708) - once we properly decode a foreign
-                                            // crate's `SyntaxContext::root`, then we can replace
-                                            // this with just `span.edition()`. A
-                                            // `SyntaxContext::root()` from the current crate will
-                                            // have the edition of the current crate, and a
-                                            // `SyntaxContext::root()` from a foreign crate will
-                                            // have the edition of that crate (which we manually
-                                            // retrieve via the `edition` parameter).
-                                            if !span.from_expansion() {
-                                                edition
-                                            } else {
-                                                span.edition()
-                                            }
-                                        })
-                                        .unwrap_or_else(
-                                            || {
+                                        token::NonterminalKind::from_symbol(fragment.name, edition)
+                                            .unwrap_or_else(|| {
+                                                let help = match fragment.name {
+                                                    sym::expr_2021 => {
+                                                        format!(
+                                                            "fragment specifier `expr_2021` \
+                                                             requires Rust 2021 or later\n\
+                                                             {VALID_FRAGMENT_NAMES_MSG}"
+                                                        )
+                                                    }
+                                                    _ if edition().at_least_rust_2021()
+                                                        && features
+                                                            .expr_fragment_specifier_2024 =>
+                                                    {
+                                                        VALID_FRAGMENT_NAMES_MSG_2021.into()
+                                                    }
+                                                    _ => VALID_FRAGMENT_NAMES_MSG.into(),
+                                                };
                                                 sess.dcx().emit_err(
                                                     errors::InvalidFragmentSpecifier {
                                                         span,
                                                         fragment,
-                                                        help: VALID_FRAGMENT_NAMES_MSG.into(),
+                                                        help,
                                                     },
                                                 );
                                                 token::NonterminalKind::Ident
-                                            },
-                                        );
+                                            });
+                                    if kind == token::NonterminalKind::Expr2021
+                                        && !features.expr_fragment_specifier_2024
+                                    {
+                                        rustc_session::parse::feature_err(
+                                            sess,
+                                            sym::expr_fragment_specifier_2024,
+                                            span,
+                                            "fragment specifier `expr_2021` is unstable",
+                                        )
+                                        .emit();
+                                    }
                                     result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
                                     continue;
                                 }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 60b386acf91..c6fc9de119d 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -458,6 +458,8 @@ declare_features! (
     (unstable, exhaustive_patterns, "1.13.0", Some(51085)),
     /// Allows explicit tail calls via `become` expression.
     (incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
+    /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
+    (incomplete, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)),
     /// Allows using `efiapi`, `sysv64` and `win64` as calling convention
     /// for functions with varargs.
     (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6e4cef068c5..2f4dcdbdf2b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2604,7 +2604,7 @@ impl PrimTy {
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct BareFnTy<'hir> {
-    pub unsafety: Unsafety,
+    pub safety: Safety,
     pub abi: Abi,
     pub generic_params: &'hir [GenericParam<'hir>],
     pub decl: &'hir FnDecl<'hir>,
@@ -3172,9 +3172,9 @@ impl<'hir> Item<'hir> {
             ItemKind::Union(data, gen), (data, gen);
 
         expect_trait,
-            (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
-            ItemKind::Trait(is_auto, unsafety, gen, bounds, items),
-            (*is_auto, *unsafety, gen, bounds, items);
+            (IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
+            ItemKind::Trait(is_auto, safety, gen, bounds, items),
+            (*is_auto, *safety, gen, bounds, items);
 
         expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>),
             ItemKind::TraitAlias(gen, bounds), (gen, bounds);
@@ -3185,25 +3185,25 @@ impl<'hir> Item<'hir> {
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
-pub enum Unsafety {
+pub enum Safety {
     Unsafe,
-    Normal,
+    Safe,
 }
 
-impl Unsafety {
-    pub fn prefix_str(&self) -> &'static str {
+impl Safety {
+    pub fn prefix_str(self) -> &'static str {
         match self {
             Self::Unsafe => "unsafe ",
-            Self::Normal => "",
+            Self::Safe => "",
         }
     }
 }
 
-impl fmt::Display for Unsafety {
+impl fmt::Display for Safety {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(match *self {
             Self::Unsafe => "unsafe",
-            Self::Normal => "normal",
+            Self::Safe => "safe",
         })
     }
 }
@@ -3225,7 +3225,7 @@ impl fmt::Display for Constness {
 
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub struct FnHeader {
-    pub unsafety: Unsafety,
+    pub safety: Safety,
     pub constness: Constness,
     pub asyncness: IsAsync,
     pub abi: Abi,
@@ -3241,7 +3241,7 @@ impl FnHeader {
     }
 
     pub fn is_unsafe(&self) -> bool {
-        matches!(&self.unsafety, Unsafety::Unsafe)
+        matches!(&self.safety, Safety::Unsafe)
     }
 }
 
@@ -3284,7 +3284,7 @@ pub enum ItemKind<'hir> {
     /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
     Union(VariantData<'hir>, &'hir Generics<'hir>),
     /// A trait definition.
-    Trait(IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
+    Trait(IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
     /// A trait alias.
     TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>),
 
@@ -3294,7 +3294,7 @@ pub enum ItemKind<'hir> {
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct Impl<'hir> {
-    pub unsafety: Unsafety,
+    pub safety: Safety,
     pub polarity: ImplPolarity,
     pub defaultness: Defaultness,
     // We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 664784cd2c6..b202ea8dca3 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -545,7 +545,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id()));
         }
         ItemKind::Impl(Impl {
-            unsafety: _,
+            safety: _,
             defaultness: _,
             polarity: _,
             defaultness_span: _,
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 5562b81871f..38ecd7dd082 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -2,7 +2,7 @@
 //! [`rustc_middle::ty`] form.
 
 use rustc_hir::LangItem;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::Span;
 
 /// Collects together a list of type bounds. These lists of bounds occur in many places
@@ -34,7 +34,7 @@ impl<'tcx> Bounds<'tcx> {
         span: Span,
     ) {
         self.clauses
-            .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span));
+            .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).upcast(tcx), span));
     }
 
     pub fn push_trait_bound(
@@ -49,7 +49,7 @@ impl<'tcx> Bounds<'tcx> {
                 .map_bound(|trait_ref| {
                     ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
                 })
-                .to_predicate(tcx),
+                .upcast(tcx),
             span,
         );
         // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
@@ -67,7 +67,7 @@ impl<'tcx> Bounds<'tcx> {
         span: Span,
     ) {
         self.clauses.push((
-            projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx),
+            projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).upcast(tcx),
             span,
         ));
     }
@@ -76,7 +76,7 @@ impl<'tcx> Bounds<'tcx> {
         let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
         let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
         // Preferable to put this obligation first, since we report better errors for sized ambiguity.
-        self.clauses.insert(0, (trait_ref.to_predicate(tcx), span));
+        self.clauses.insert(0, (trait_ref.upcast(tcx), span));
     }
 
     pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
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 39940c8f0f3..44bf8fd2d93 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -14,7 +14,7 @@ use rustc_infer::traits::{util, FulfillmentError};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
     self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
@@ -2211,7 +2211,7 @@ fn param_env_with_gat_bounds<'tcx>(
                     },
                     bound_vars,
                 )
-                .to_predicate(tcx),
+                .upcast(tcx),
             ),
         };
     }
@@ -2250,7 +2250,7 @@ fn try_report_async_mismatch<'tcx>(
     for error in errors {
         if let ObligationCauseCode::WhereClause(def_id, _) = *error.root_obligation.cause.code()
             && def_id == async_future_def_id
-            && let Some(proj) = error.root_obligation.predicate.to_opt_poly_projection_pred()
+            && let Some(proj) = error.root_obligation.predicate.as_projection_clause()
             && let Some(proj) = proj.no_bound_vars()
             && infcx.can_eq(
                 error.root_obligation.param_env,
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index e44e8e67da3..25ac31c16c7 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -156,7 +156,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         [],
         expected_return_type,
         false,
-        hir::Unsafety::Normal,
+        hir::Safety::Safe,
         Abi::Rust,
     ));
 
@@ -252,7 +252,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                 [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
                 tcx.types.isize,
                 false,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::Rust,
             ));
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 00ff470a0a7..d829e720d9e 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -71,13 +71,13 @@ fn equate_intrinsic_type<'tcx>(
 }
 
 /// Returns the unsafety of the given intrinsic.
-pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Unsafety {
+pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Safety {
     let has_safe_attr = if tcx.has_attr(intrinsic_id, sym::rustc_intrinsic) {
-        tcx.fn_sig(intrinsic_id).skip_binder().unsafety()
+        tcx.fn_sig(intrinsic_id).skip_binder().safety()
     } else {
         match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
-            true => hir::Unsafety::Normal,
-            false => hir::Unsafety::Unsafe,
+            true => hir::Safety::Safe,
+            false => hir::Safety::Unsafe,
         }
     };
     let is_in_list = match tcx.item_name(intrinsic_id.into()) {
@@ -136,8 +136,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::fmul_algebraic
         | sym::fdiv_algebraic
         | sym::frem_algebraic
-        | sym::const_eval_select => hir::Unsafety::Normal,
-        _ => hir::Unsafety::Unsafe,
+        | sym::const_eval_select => hir::Safety::Safe,
+        _ => hir::Safety::Unsafe,
     };
 
     if has_safe_attr != is_in_list {
@@ -197,7 +197,7 @@ pub fn check_intrinsic_type(
         })
     };
 
-    let (n_tps, n_lts, n_cts, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
+    let (n_tps, n_lts, n_cts, inputs, output, safety) = if name_str.starts_with("atomic_") {
         let split: Vec<&str> = name_str.split('_').collect();
         assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
 
@@ -219,9 +219,9 @@ pub fn check_intrinsic_type(
                 return;
             }
         };
-        (n_tps, 0, 0, inputs, output, hir::Unsafety::Unsafe)
+        (n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
     } else {
-        let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id);
+        let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
         let (n_tps, n_cts, inputs, output) = match intrinsic_name {
             sym::abort => (0, 0, vec![], tcx.types.never),
             sym::unreachable => (0, 0, vec![], tcx.types.never),
@@ -514,14 +514,14 @@ pub fn check_intrinsic_type(
                     [mut_u8],
                     tcx.types.unit,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     Abi::Rust,
                 ));
                 let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig(
                     [mut_u8, mut_u8],
                     tcx.types.unit,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     Abi::Rust,
                 ));
                 (
@@ -656,9 +656,9 @@ pub fn check_intrinsic_type(
                 return;
             }
         };
-        (n_tps, 0, n_cts, inputs, output, unsafety)
+        (n_tps, 0, n_cts, inputs, output, safety)
     };
-    let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, abi);
+    let sig = tcx.mk_fn_sig(inputs, output, false, safety, abi);
     let sig = ty::Binder::bind_with_vars(sig, bound_vars);
     equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, n_cts, sig)
 }
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index f8b0164b9a5..0083da2a1e4 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -456,7 +456,7 @@ fn fn_sig_suggestion<'tcx>(
 
     let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
 
-    let unsafety = sig.unsafety.prefix_str();
+    let safety = sig.safety.prefix_str();
     let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
 
     // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
@@ -464,9 +464,7 @@ fn fn_sig_suggestion<'tcx>(
     // lifetimes between the `impl` and the `trait`, but this should be good enough to
     // fill in a significant portion of the missing code, and other subsequent
     // suggestions can help the user fix the code.
-    format!(
-        "{unsafety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}"
-    )
+    format!("{safety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
 }
 
 /// Return placeholder code for the given associated item.
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b918a8c32d8..e137aab2109 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -20,8 +20,8 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast,
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_middle::{bug, span_bug};
@@ -685,7 +685,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                 // `Self: 'me`.)
                 bounds.insert(
                     ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param))
-                        .to_predicate(tcx),
+                        .upcast(tcx),
                 );
             }
         }
@@ -730,7 +730,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                         region_a_param,
                         region_b_param,
                     ))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 );
             }
         }
@@ -1350,12 +1350,12 @@ fn check_impl<'tcx>(
                         // We already have a better span.
                         continue;
                     }
-                    if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
+                    if let Some(pred) = obligation.predicate.as_trait_clause()
                         && pred.skip_binder().self_ty() == trait_ref.self_ty()
                     {
                         obligation.cause.span = hir_self_ty.span;
                     }
-                    if let Some(pred) = obligation.predicate.to_opt_poly_projection_pred()
+                    if let Some(pred) = obligation.predicate.as_projection_clause()
                         && pred.skip_binder().self_ty() == trait_ref.self_ty()
                     {
                         obligation.cause.span = hir_self_ty.span;
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index 28735429210..5fe21e9b822 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -2,7 +2,7 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc_errors::{codes::*, struct_span_code_err};
-use rustc_hir::Unsafety;
+use rustc_hir::Safety;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{ImplPolarity::*, ImplTraitHeader, TraitDef, TyCtxt};
 use rustc_span::def_id::LocalDefId;
@@ -18,8 +18,8 @@ pub(super) fn check_item(
         tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
     let trait_ref = trait_header.trait_ref.instantiate_identity();
 
-    match (trait_def.unsafety, unsafe_attr, trait_header.unsafety, trait_header.polarity) {
-        (Unsafety::Normal, None, Unsafety::Unsafe, Positive | Reservation) => {
+    match (trait_def.safety, unsafe_attr, trait_header.safety, trait_header.polarity) {
+        (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
                 tcx.dcx(),
@@ -37,7 +37,7 @@ pub(super) fn check_item(
             .emit());
         }
 
-        (Unsafety::Unsafe, _, Unsafety::Normal, Positive | Reservation) => {
+        (Safety::Unsafe, _, Safety::Safe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
                 tcx.dcx(),
@@ -61,7 +61,7 @@ pub(super) fn check_item(
             .emit());
         }
 
-        (Unsafety::Normal, Some(attr_name), Unsafety::Normal, Positive | Reservation) => {
+        (Safety::Safe, Some(attr_name), Safety::Safe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
                 tcx.dcx(),
@@ -85,14 +85,14 @@ pub(super) fn check_item(
             .emit());
         }
 
-        (_, _, Unsafety::Unsafe, Negative) => {
+        (_, _, Safety::Unsafe, Negative) => {
             // Reported in AST validation
             assert!(tcx.dcx().has_errors().is_some(), "unsafe negative impl");
             Ok(())
         }
-        (_, _, Unsafety::Normal, Negative)
-        | (Unsafety::Unsafe, _, Unsafety::Unsafe, Positive | Reservation)
-        | (Unsafety::Normal, Some(_), Unsafety::Unsafe, Positive | Reservation)
-        | (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()),
+        (_, _, Safety::Safe, Negative)
+        | (Safety::Unsafe, _, Safety::Unsafe, Positive | Reservation)
+        | (Safety::Safe, Some(_), Safety::Unsafe, Positive | Reservation)
+        | (Safety::Safe, None, Safety::Safe, _) => Ok(()),
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 0b9f7fd41fb..aa28b2c8e2c 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -29,7 +29,7 @@ use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -1102,11 +1102,11 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
 fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     let item = tcx.hir().expect_item(def_id);
 
-    let (is_auto, unsafety, items) = match item.kind {
-        hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
-            (is_auto == hir::IsAuto::Yes, unsafety, items)
+    let (is_auto, safety, items) = match item.kind {
+        hir::ItemKind::Trait(is_auto, safety, .., items) => {
+            (is_auto == hir::IsAuto::Yes, safety, items)
         }
-        hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal, &[][..]),
+        hir::ItemKind::TraitAlias(..) => (false, hir::Safety::Safe, &[][..]),
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
@@ -1247,7 +1247,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 
     ty::TraitDef {
         def_id: def_id.to_def_id(),
-        unsafety,
+        safety,
         paren_sugar,
         has_auto_impl: is_auto,
         is_marker,
@@ -1286,7 +1286,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             {
                 icx.lowerer().lower_fn_ty(
                     hir_id,
-                    sig.header.unsafety,
+                    sig.header.safety,
                     sig.header.abi,
                     sig.decl,
                     Some(generics),
@@ -1301,14 +1301,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
             generics,
             ..
-        }) => icx.lowerer().lower_fn_ty(
-            hir_id,
-            header.unsafety,
-            header.abi,
-            decl,
-            Some(generics),
-            None,
-        ),
+        }) => {
+            icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
+        }
 
         ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
@@ -1321,8 +1316,8 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id).instantiate_identity());
             // constructors for structs with `layout_scalar_valid_range` are unsafe to call
             let safety = match tcx.layout_scalar_valid_range(adt_def_id) {
-                (Bound::Unbounded, Bound::Unbounded) => hir::Unsafety::Normal,
-                _ => hir::Unsafety::Unsafe,
+                (Bound::Unbounded, Bound::Unbounded) => hir::Safety::Safe,
+                _ => hir::Safety::Unsafe,
             };
             ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, abi::Abi::Rust))
         }
@@ -1409,13 +1404,13 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                 fn_sig.inputs().iter().copied(),
                 recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
                 fn_sig.c_variadic,
-                fn_sig.unsafety,
+                fn_sig.safety,
                 fn_sig.abi,
             ))
         }
         None => icx.lowerer().lower_fn_ty(
             hir_id,
-            sig.header.unsafety,
+            sig.header.safety,
             sig.header.abi,
             sig.decl,
             Some(generics),
@@ -1574,7 +1569,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
             };
             ty::ImplTraitHeader {
                 trait_ref: ty::EarlyBinder::bind(trait_ref),
-                unsafety: impl_.unsafety,
+                safety: impl_.safety,
                 polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
             }
         })
@@ -1665,7 +1660,7 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
             def_id, inferred_outlives,
         );
         let inferred_outlives_iter =
-            inferred_outlives.iter().map(|(clause, span)| ((*clause).to_predicate(tcx), *span));
+            inferred_outlives.iter().map(|(clause, span)| ((*clause).upcast(tcx), *span));
         if result.predicates.is_empty() {
             result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter);
         } else {
@@ -1685,14 +1680,14 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     decl: &'tcx hir::FnDecl<'tcx>,
     abi: abi::Abi,
 ) -> ty::PolyFnSig<'tcx> {
-    let unsafety = if abi == abi::Abi::RustIntrinsic {
+    let safety = if abi == abi::Abi::RustIntrinsic {
         intrinsic_operation_unsafety(tcx, def_id)
     } else {
-        hir::Unsafety::Unsafe
+        hir::Safety::Unsafe
     };
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let fty =
-        ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, unsafety, abi, decl, None, None);
+        ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, safety, abi, decl, None, None);
 
     // Feature gate SIMD types in FFI, since I am not sure that the
     // ABIs are handled at all correctly. -huonw
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index d348d6f789f..db36aba7edf 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -9,7 +9,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate};
+use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
@@ -40,11 +40,13 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
         // `tcx.def_span(def_id);`
         let span = DUMMY_SP;
 
-        result.predicates =
-            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
-                span,
-            ))));
+        result.predicates = tcx.arena.alloc_from_iter(
+            result
+                .predicates
+                .iter()
+                .copied()
+                .chain(std::iter::once((ty::TraitRef::identity(tcx, def_id).upcast(tcx), span))),
+        );
     }
     debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
     result
@@ -165,7 +167,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // (see below). Recall that a default impl is not itself an impl, but rather a
     // set of defaults that can be incorporated into another impl.
     if let Some(trait_ref) = is_default_impl_trait {
-        predicates.insert((trait_ref.to_predicate(tcx), tcx.def_span(def_id)));
+        predicates.insert((trait_ref.upcast(tcx), tcx.def_span(def_id)));
     }
 
     // Collect the predicates that were written inline by the user on each
@@ -196,10 +198,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     .no_bound_vars()
                     .expect("const parameters cannot be generic");
                 let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty);
-                predicates.insert((
-                    ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx),
-                    param.span,
-                ));
+                predicates
+                    .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));
             }
         }
     }
@@ -228,7 +228,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                             ty::ClauseKind::WellFormed(ty.into()),
                             bound_vars,
                         );
-                        predicates.insert((predicate.to_predicate(tcx), span));
+                        predicates.insert((predicate.upcast(tcx), span));
                     }
                 }
 
@@ -257,8 +257,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                             )
                         }
                     };
-                    let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
-                        .to_predicate(tcx);
+                    let pred =
+                        ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)).upcast(tcx);
                     (pred, span)
                 }))
             }
@@ -328,12 +328,12 @@ fn compute_bidirectional_outlives_predicates<'tcx>(
             let span = tcx.def_span(param.def_id);
             predicates.push((
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_lifetime, dup_lifetime))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 span,
             ));
             predicates.push((
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_lifetime, orig_lifetime))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 span,
             ));
         }
@@ -354,8 +354,7 @@ fn const_evaluatable_predicates_of(
             let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
             if let ty::ConstKind::Unevaluated(_) = ct.kind() {
                 let span = self.tcx.def_span(c.def_id);
-                self.preds
-                    .insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span));
+                self.preds.insert((ty::ClauseKind::ConstEvaluatable(ct).upcast(self.tcx), span));
             }
         }
 
@@ -694,7 +693,7 @@ pub(super) fn type_param_predicates(
         && param_id == item_hir_id
     {
         let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id.to_def_id());
-        extend = Some((identity_trait_ref.to_predicate(tcx), item.span));
+        extend = Some((identity_trait_ref.upcast(tcx), item.span));
     }
 
     let icx = ItemCtxt::new(tcx, item_def_id);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index d16648b9e8f..39016d15236 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2080,14 +2080,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 Ty::new_fn_ptr(
                     tcx,
-                    self.lower_fn_ty(
-                        hir_ty.hir_id,
-                        bf.unsafety,
-                        bf.abi,
-                        bf.decl,
-                        None,
-                        Some(hir_ty),
-                    ),
+                    self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
                 )
             }
             hir::TyKind::TraitObject(bounds, lifetime, repr) => {
@@ -2309,11 +2302,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     /// Lower a function type from the HIR to our internal notion of a function signature.
-    #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
+    #[instrument(level = "debug", skip(self, hir_id, safety, abi, decl, generics, hir_ty), ret)]
     pub fn lower_fn_ty(
         &self,
         hir_id: HirId,
-        unsafety: hir::Unsafety,
+        safety: hir::Safety,
         abi: abi::Abi,
         decl: &hir::FnDecl<'tcx>,
         generics: Option<&hir::Generics<'_>>,
@@ -2376,7 +2369,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         debug!(?output_ty);
 
-        let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi);
+        let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
         let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
 
         if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index 30b99a095f3..4f7a39d0250 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -9,7 +9,7 @@ use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
 use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable};
-use rustc_middle::ty::{DynKind, ToPredicate};
+use rustc_middle::ty::{DynKind, Upcast};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
@@ -119,7 +119,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
         for (base_trait_ref, span) in regular_traits_refs_spans {
-            let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
+            let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
             for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() {
                 debug!("observing object predicate `{pred:?}`");
 
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index a87112dcc12..97fd7731b1e 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -2,7 +2,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
+use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt, Upcast};
 use rustc_span::Span;
 
 mod explicit;
@@ -75,14 +75,14 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
                         match kind1.unpack() {
                             GenericArgKind::Type(ty1) => Some((
                                 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2))
-                                    .to_predicate(tcx),
+                                    .upcast(tcx),
                                 span,
                             )),
                             GenericArgKind::Lifetime(region1) => Some((
                                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
                                     region1, *region2,
                                 ))
-                                .to_predicate(tcx),
+                                .upcast(tcx),
                                 span,
                             )),
                             GenericArgKind::Const(_) => {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index a47e6af0bf2..29c7e576d2b 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -287,7 +287,7 @@ impl<'a> State<'a> {
                 self.pclose();
             }
             hir::TyKind::BareFn(f) => {
-                self.print_ty_fn(f.abi, f.unsafety, f.decl, None, f.generic_params, f.param_names);
+                self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names);
             }
             hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
@@ -351,7 +351,7 @@ impl<'a> State<'a> {
                 self.print_fn(
                     decl,
                     hir::FnHeader {
-                        unsafety: hir::Unsafety::Normal,
+                        safety: hir::Safety::Safe,
                         constness: hir::Constness::NotConst,
                         abi: Abi::Rust,
                         asyncness: hir::IsAsync::NotAsync,
@@ -582,7 +582,7 @@ impl<'a> State<'a> {
                 self.print_struct(struct_def, generics, item.ident.name, item.span, true);
             }
             hir::ItemKind::Impl(&hir::Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 defaultness_span: _,
@@ -593,7 +593,7 @@ impl<'a> State<'a> {
             }) => {
                 self.head("");
                 self.print_defaultness(defaultness);
-                self.print_unsafety(unsafety);
+                self.print_safety(safety);
                 self.word_nbsp("impl");
 
                 if !generics.params.is_empty() {
@@ -622,10 +622,10 @@ impl<'a> State<'a> {
                 }
                 self.bclose(item.span);
             }
-            hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, trait_items) => {
+            hir::ItemKind::Trait(is_auto, safety, generics, bounds, trait_items) => {
                 self.head("");
                 self.print_is_auto(is_auto);
-                self.print_unsafety(unsafety);
+                self.print_safety(safety);
                 self.word_nbsp("trait");
                 self.print_ident(item.ident);
                 self.print_generic_params(generics.params);
@@ -2234,7 +2234,7 @@ impl<'a> State<'a> {
     fn print_ty_fn(
         &mut self,
         abi: Abi,
-        unsafety: hir::Unsafety,
+        safety: hir::Safety,
         decl: &hir::FnDecl<'_>,
         name: Option<Symbol>,
         generic_params: &[hir::GenericParam<'_>],
@@ -2246,7 +2246,7 @@ impl<'a> State<'a> {
         self.print_fn(
             decl,
             hir::FnHeader {
-                unsafety,
+                safety,
                 abi,
                 constness: hir::Constness::NotConst,
                 asyncness: hir::IsAsync::NotAsync,
@@ -2267,7 +2267,7 @@ impl<'a> State<'a> {
             hir::IsAsync::Async(_) => self.word_nbsp("async"),
         }
 
-        self.print_unsafety(header.unsafety);
+        self.print_safety(header.safety);
 
         if header.abi != Abi::Rust {
             self.word_nbsp("extern");
@@ -2284,10 +2284,10 @@ impl<'a> State<'a> {
         }
     }
 
-    fn print_unsafety(&mut self, s: hir::Unsafety) {
+    fn print_safety(&mut self, s: hir::Safety) {
         match s {
-            hir::Unsafety::Normal => {}
-            hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
+            hir::Safety::Safe => {}
+            hir::Safety::Unsafe => self.word_nbsp("unsafe"),
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 502a176845e..9736c8b8920 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -201,7 +201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         tupled_upvars_ty,
                     ),
                     coroutine_closure_sig.c_variadic,
-                    coroutine_closure_sig.unsafety,
+                    coroutine_closure_sig.safety,
                     coroutine_closure_sig.abi,
                 );
                 let adjustments = self.adjust_steps(autoderef);
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 89e64cf5f0d..843d9e38714 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -216,7 +216,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>
         ty::BoundVariableKind::Region(ty::BrAnon),
     ]);
     let expected_sig = ty::Binder::bind_with_vars(
-        tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.unsafety, Abi::Rust),
+        tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.safety, Abi::Rust),
         bounds,
     );
 
@@ -239,7 +239,7 @@ fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id:
     let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
     let main_fn_ty = Ty::new_fn_ptr(
         tcx,
-        Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust)),
+        Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Safety::Safe, Abi::Rust)),
     );
 
     let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
@@ -251,7 +251,7 @@ fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id:
         ],
         tcx.types.isize,
         false,
-        fn_sig.unsafety,
+        fn_sig.safety,
         Abi::Rust,
     ));
 
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index aca069d8fb5..14a6177141c 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -89,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         [Ty::new_tup(tcx, sig.inputs())],
                         sig.output(),
                         sig.c_variadic,
-                        sig.unsafety,
+                        sig.safety,
                         sig.abi,
                     )
                 });
@@ -238,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     ],
                                     Ty::new_tup(tcx, &[bound_yield_ty, bound_return_ty]),
                                     sig.c_variadic,
-                                    sig.unsafety,
+                                    sig.safety,
                                     sig.abi,
                                 )
                             }),
@@ -281,7 +281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     liberated_sig.inputs().iter().copied(),
                     coroutine_output_ty,
                     liberated_sig.c_variadic,
-                    liberated_sig.unsafety,
+                    liberated_sig.safety,
                     liberated_sig.abi,
                 );
 
@@ -493,7 +493,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             input_tys,
             ret_param_ty,
             false,
-            hir::Unsafety::Normal,
+            hir::Safety::Safe,
             Abi::Rust,
         ));
 
@@ -605,7 +605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 sig.inputs().iter().cloned(),
                 sig.output(),
                 sig.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::RustCall,
             )
         });
@@ -743,7 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 inputs,
                 supplied_output_ty,
                 expected_sigs.liberated_sig.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::RustCall,
             );
 
@@ -820,7 +820,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 supplied_arguments,
                 supplied_return,
                 decl.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::RustCall,
             ),
             bound_vars,
@@ -984,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             supplied_arguments,
             err_ty,
             decl.c_variadic,
-            hir::Unsafety::Normal,
+            hir::Safety::Safe,
             Abi::RustCall,
         ));
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 8d93f402f10..d81dab2222a 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -788,8 +788,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             let outer_universe = self.infcx.universe();
 
             let result = if let ty::FnPtr(fn_ty_b) = b.kind()
-                && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
-                    (fn_ty_a.unsafety(), fn_ty_b.unsafety())
+                && let (hir::Safety::Safe, hir::Safety::Unsafe) =
+                    (fn_ty_a.safety(), fn_ty_b.safety())
             {
                 let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
                 self.unify_and(unsafe_a, b, to_unsafe)
@@ -851,7 +851,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
                     // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
 
-                    if b_sig.unsafety() == hir::Unsafety::Normal
+                    if b_sig.safety() == hir::Safety::Safe
                         && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
                     {
                         return Err(TypeError::TargetFeatureCast(def_id));
@@ -922,14 +922,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 // or
                 //     `unsafe fn(arg0,arg1,...) -> _`
                 let closure_sig = args_a.as_closure().sig();
-                let unsafety = fn_ty.unsafety();
+                let safety = fn_ty.safety();
                 let pointer_ty =
-                    Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, unsafety));
+                    Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, safety));
                 debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
                 self.unify_and(
                     pointer_ty,
                     b,
-                    simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(unsafety))),
+                    simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
                 )
             }
             _ => self.unify_and(a, b, identity),
@@ -1126,27 +1126,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (ty::Closure(_, args), ty::FnDef(..)) => {
                         let b_sig = new_ty.fn_sig(self.tcx);
                         let a_sig =
-                            self.tcx.signature_unclosure(args.as_closure().sig(), b_sig.unsafety());
+                            self.tcx.signature_unclosure(args.as_closure().sig(), b_sig.safety());
                         (Some(a_sig), Some(b_sig))
                     }
                     (ty::FnDef(..), ty::Closure(_, args)) => {
                         let a_sig = prev_ty.fn_sig(self.tcx);
                         let b_sig =
-                            self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.unsafety());
+                            self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.safety());
                         (Some(a_sig), Some(b_sig))
                     }
-                    (ty::Closure(_, args_a), ty::Closure(_, args_b)) => {
-                        (
-                            Some(self.tcx.signature_unclosure(
-                                args_a.as_closure().sig(),
-                                hir::Unsafety::Normal,
-                            )),
-                            Some(self.tcx.signature_unclosure(
-                                args_b.as_closure().sig(),
-                                hir::Unsafety::Normal,
-                            )),
-                        )
-                    }
+                    (ty::Closure(_, args_a), ty::Closure(_, args_b)) => (
+                        Some(
+                            self.tcx
+                                .signature_unclosure(args_a.as_closure().sig(), hir::Safety::Safe),
+                        ),
+                        Some(
+                            self.tcx
+                                .signature_unclosure(args_b.as_closure().sig(), hir::Safety::Safe),
+                        ),
+                    ),
                     _ => (None, None),
                 }
             }
@@ -1168,14 +1166,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let fn_ptr = Ty::new_fn_ptr(self.tcx, sig);
             let prev_adjustment = match prev_ty.kind() {
                 ty::Closure(..) => {
-                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.unsafety()))
+                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.safety()))
                 }
                 ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
                 _ => span_bug!(cause.span, "should not try to coerce a {prev_ty} to a fn pointer"),
             };
             let next_adjustment = match new_ty.kind() {
                 ty::Closure(..) => {
-                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.unsafety()))
+                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.safety()))
                 }
                 ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
                 _ => span_bug!(new.span, "should not try to coerce a {new_ty} to a fn pointer"),
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index c79b6be6560..e456bd7fd4a 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -558,7 +558,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
                     if let Some(def_id) = typeck_results.type_dependent_def_id(ex.hir_id)
                         && let method_ty = self.root_ctxt.tcx.type_of(def_id).instantiate_identity()
                         && let sig = method_ty.fn_sig(self.root_ctxt.tcx)
-                        && let hir::Unsafety::Unsafe = sig.unsafety()
+                        && let hir::Safety::Unsafe = sig.safety()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Method),
@@ -578,7 +578,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
 
                     if func_ty.is_fn()
                         && let sig = func_ty.fn_sig(self.root_ctxt.tcx)
-                        && let hir::Unsafety::Unsafe = sig.unsafety()
+                        && let hir::Safety::Unsafe = sig.safety()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Call),
@@ -609,7 +609,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
                     // `is_fn` excludes closures, but those can't be unsafe.
                     if ty.is_fn()
                         && let sig = ty.fn_sig(self.root_ctxt.tcx)
-                        && let hir::Unsafety::Unsafe = sig.unsafety()
+                        && let hir::Safety::Unsafe = sig.safety()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Path),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index ac1e26df870..23f4d3c36a3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -1,7 +1,7 @@
 //! A utility module to inspect currently ambiguous obligations in the current context.
 use crate::FnCtxt;
-use rustc_infer::traits::solve::Goal;
 use rustc_infer::traits::{self, ObligationCause};
+use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_span::Span;
 use rustc_trait_selection::solve::inspect::ProofTreeInferCtxtExt;
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index fe0dd4e393f..56e13cd679d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -28,8 +28,8 @@ use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::span_bug;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self, suggest_constraining_type_params, Article, Binder, IsSuggestable, ToPredicate, Ty,
-    TypeVisitableExt,
+    self, suggest_constraining_type_params, Article, Binder, IsSuggestable, Ty, TypeVisitableExt,
+    Upcast,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
@@ -1716,7 +1716,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                 }
-                self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
+                self.suggest_derive(diag, &[(trait_ref.upcast(self.tcx), None, None)]);
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 6892da7a5e2..b9a99fbec3c 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -145,7 +145,7 @@ fn typeck_with_fallback<'tcx>(
 
     if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
         let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
-            fcx.lowerer().lower_fn_ty(id, header.unsafety, header.abi, decl, None, None)
+            fcx.lowerer().lower_fn_ty(id, header.safety, header.abi, decl, None, None)
         } else {
             tcx.fn_sig(def_id).instantiate_identity()
         };
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 6cfdacf6a24..fc652490a40 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -21,7 +21,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::AssocItem;
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_middle::{bug, span_bug};
@@ -1496,7 +1496,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         }
                     }
 
-                    trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx));
+                    trait_predicate = Some(trait_ref.upcast(self.tcx));
                 }
                 ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => {
                     let trait_ref = self.instantiate_binder_with_fresh_vars(
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index e371775be0a..87b76b978b9 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -583,7 +583,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if !errors.is_empty() {
                             for error in errors {
                                 if let Some(trait_pred) =
-                                    error.obligation.predicate.to_opt_poly_trait_pred()
+                                    error.obligation.predicate.as_trait_clause()
                                 {
                                     let output_associated_item = match error.obligation.cause.code()
                                     {
@@ -797,9 +797,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     );
 
                     if operand_ty.has_non_region_param() {
-                        let predicates = errors.iter().filter_map(|error| {
-                            error.obligation.predicate.to_opt_poly_trait_pred()
-                        });
+                        let predicates = errors
+                            .iter()
+                            .filter_map(|error| error.obligation.predicate.as_trait_clause());
                         for pred in predicates {
                             self.err_ctxt().suggest_restricting_param_bound(
                                 &mut err,
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index d313c0eafe1..9d16f0d4815 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -419,7 +419,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         [],
                         tupled_upvars_ty_for_borrow,
                         false,
-                        hir::Unsafety::Normal,
+                        hir::Safety::Safe,
                         rustc_target::spec::abi::Abi::Rust,
                     ),
                     self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index eaef715fe5d..16057b6ad9d 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -385,19 +385,31 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        use GenericArgKind::*;
         TypeTrace {
             cause: cause.clone(),
             values: match (a.unpack(), b.unpack()) {
-                (Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)),
-                (Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
-                (Const(a), Const(b)) => {
+                (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
+                    Regions(ExpectedFound::new(a_is_expected, a, b))
+                }
+                (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
+                    Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
+                }
+                (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
                     Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
                 }
 
-                (Lifetime(_), Type(_) | Const(_))
-                | (Type(_), Lifetime(_) | Const(_))
-                | (Const(_), Lifetime(_) | Type(_)) => {
+                (
+                    GenericArgKind::Lifetime(_),
+                    GenericArgKind::Type(_) | GenericArgKind::Const(_),
+                )
+                | (
+                    GenericArgKind::Type(_),
+                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_),
+                )
+                | (
+                    GenericArgKind::Const(_),
+                    GenericArgKind::Lifetime(_) | GenericArgKind::Type(_),
+                ) => {
                     bug!("relating different kinds: {a:?} {b:?}")
                 }
             },
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index d0687dfc6fd..46a7e7b2399 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -73,7 +73,7 @@ use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _};
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
     self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -516,7 +516,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                     RegionResolutionError::CannotNormalize(clause, origin) => {
                         let clause: ty::Clause<'tcx> =
-                            clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx);
+                            clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
                         self.tcx
                             .dcx()
                             .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
@@ -1053,8 +1053,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
         // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
         // ^^^^^^
-        values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
-        values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
+        values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety);
+        values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety);
 
         // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
         //        ^^^^^^^^^^
@@ -1928,7 +1928,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                     self.tcx
                                         .signature_unclosure(
                                             args.as_closure().sig(),
-                                            rustc_hir::Unsafety::Normal,
+                                            rustc_hir::Safety::Safe,
                                         )
                                         .to_string(),
                                 ),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index b4decbf14a2..98fd7906e70 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -168,7 +168,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> {
                 let closure_sig = args.as_closure().sig();
                 Ty::new_fn_ptr(
                     self.tcx,
-                    self.tcx.signature_unclosure(closure_sig, hir::Unsafety::Normal),
+                    self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe),
                 )
             }
             _ => ty.super_fold_with(self),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 8859772848f..e125f1858dd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -409,10 +409,8 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
             {
                 let closure_sig = self_ty.map(|closure| {
                     if let ty::Closure(_, args) = closure.kind() {
-                        self.tcx().signature_unclosure(
-                            args.as_closure().sig(),
-                            rustc_hir::Unsafety::Normal,
-                        )
+                        self.tcx()
+                            .signature_unclosure(args.as_closure().sig(), rustc_hir::Safety::Safe)
                     } else {
                         bug!("type is not longer closure");
                     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index c24ad1fa1e7..f2fe43380b8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -452,7 +452,7 @@ impl<T> Trait<T> for X {
                     }
                     (ty::FnPtr(sig), ty::FnDef(def_id, _))
                     | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
-                        if tcx.fn_sig(def_id).skip_binder().unsafety() < sig.unsafety() {
+                        if tcx.fn_sig(def_id).skip_binder().safety() < sig.safety() {
                             diag.note(
                                 "unsafe functions cannot be coerced into safe function pointers",
                             );
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index c1baadfa8df..101598c5951 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -29,7 +29,7 @@ use rustc_middle::infer::canonical::OriginalQueryValues;
 use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
-use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::Span;
 
@@ -337,7 +337,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         self.obligations.extend(obligations);
     }
 
-    pub fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>) {
+    pub fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.obligations.extend(obligations.into_iter().map(|to_pred| {
             Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
         }))
@@ -360,7 +363,10 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
     /// Register predicates that must hold in order for this relation to hold. Uses
     /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
     /// be used if control over the obligation causes is required.
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    );
 
     /// Register `AliasRelate` obligation(s) that both types must be related to each other.
     fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
index b86d1b2671d..a224a86492a 100644
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ b/compiler/rustc_infer/src/infer/relate/glb.rs
@@ -140,7 +140,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
         self.fields.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
index 20f5f65c984..83ab7770770 100644
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ b/compiler/rustc_infer/src/infer/relate/lub.rs
@@ -140,7 +140,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
         self.fields.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index 86a24eef7f5..21064fff97f 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -312,7 +312,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
         self.structurally_relate_aliases
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index cb067c7a660..e27e6a0a4a1 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -2,7 +2,7 @@ use crate::infer::InferCtxt;
 use crate::traits::Obligation;
 use rustc_hir::def_id::DefId;
 use rustc_macros::extension;
-use rustc_middle::ty::{self, ToPredicate, Ty};
+use rustc_middle::ty::{self, Ty, Upcast};
 
 use super::FulfillmentError;
 use super::{ObligationCause, PredicateObligation};
@@ -26,7 +26,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: ty::Binder::dummy(trait_ref).to_predicate(infcx.tcx),
+                predicate: trait_ref.upcast(infcx.tcx),
             },
         );
     }
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index f77a92bf9bc..0ae4340098b 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -16,7 +16,7 @@ use rustc_hir as hir;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt, Upcast};
 use rustc_span::Span;
 
 pub use self::ImplSource::*;
@@ -155,7 +155,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
         tcx: TyCtxt<'tcx>,
         cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, O>,
+        predicate: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
         Self::with_depth(tcx, cause, 0, param_env, predicate)
     }
@@ -173,9 +173,9 @@ impl<'tcx, O> Obligation<'tcx, O> {
         cause: ObligationCause<'tcx>,
         recursion_depth: usize,
         param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, O>,
+        predicate: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
-        let predicate = predicate.to_predicate(tcx);
+        let predicate = predicate.upcast(tcx);
         Obligation { cause, param_env, recursion_depth, predicate }
     }
 
@@ -184,7 +184,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
         span: Span,
         body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: impl ToPredicate<'tcx, O>,
+        trait_ref: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
         Obligation::new(tcx, ObligationCause::misc(span, body_id), param_env, trait_ref)
     }
@@ -192,7 +192,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
     pub fn with<P>(
         &self,
         tcx: TyCtxt<'tcx>,
-        value: impl ToPredicate<'tcx, P>,
+        value: impl Upcast<TyCtxt<'tcx>, P>,
     ) -> Obligation<'tcx, P> {
         Obligation::with_depth(tcx, self.cause.clone(), self.recursion_depth, self.param_env, value)
     }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index d8d84b777e0..cc12a4bf091 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -3,7 +3,7 @@ use smallvec::smallvec;
 use crate::infer::outlives::components::{push_outlives_components, Component};
 use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -357,9 +357,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
                                 None
                             }
                         })
-                        .map(|clause| {
-                            elaboratable.child(bound_clause.rebind(clause).to_predicate(tcx))
-                        }),
+                        .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))),
                 );
             }
             ty::ClauseKind::RegionOutlives(..) => {
@@ -409,14 +407,14 @@ pub fn supertraits<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
+    elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
 }
 
 pub fn transitive_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
         .filter_only_self()
         .filter_to_traits()
 }
@@ -431,7 +429,7 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
     assoc_name: Ident,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
         .filter_only_self_that_defines(assoc_name)
         .filter_to_traits()
 }
@@ -457,7 +455,7 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
         while let Some(pred) = self.base_iterator.next() {
-            if let Some(data) = pred.to_opt_poly_trait_pred() {
+            if let Some(data) = pred.as_trait_clause() {
                 return Some(data.map_bound(|t| t.trait_ref));
             }
         }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index b9be92b89af..6b9f9d1531e 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -57,8 +57,8 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeVisitableExt;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
 use rustc_session::lint::{BuiltinLintDiag, FutureIncompatibilityReason};
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
@@ -360,11 +360,11 @@ impl EarlyLintPass for UnsafeCode {
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         match it.kind {
-            ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
+            ast::ItemKind::Trait(box ast::Trait { safety: ast::Safety::Unsafe(_), .. }) => {
                 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
             }
 
-            ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
+            ast::ItemKind::Impl(box ast::Impl { safety: ast::Safety::Unsafe(_), .. }) => {
                 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
             }
 
@@ -419,7 +419,7 @@ impl EarlyLintPass for UnsafeCode {
         if let FnKind::Fn(
             ctxt,
             _,
-            ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
+            ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
             _,
             _,
             body,
@@ -734,7 +734,7 @@ fn type_implements_negative_copy_modulo_regions<'tcx>(
         cause: traits::ObligationCause::dummy(),
         param_env,
         recursion_depth: 0,
-        predicate: ty::Binder::dummy(pred).to_predicate(tcx),
+        predicate: pred.upcast(tcx),
     };
 
     tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 48e5683fc0a..2c86964feef 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -345,8 +345,8 @@ fn structurally_same_type_impl<'tcx>(
                     let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig);
                     let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig);
 
-                    (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
-                        == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+                    (a_sig.abi, a_sig.safety, a_sig.c_variadic)
+                        == (b_sig.abi, b_sig.safety, b_sig.c_variadic)
                         && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
                             structurally_same_type_impl(seen_types, tcx, param_env, *a, *b, ckind)
                         })
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index d1cdabc293d..ab0c598ea0c 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -28,6 +28,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
+rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 13719268737..7392eb6c2bb 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -61,7 +61,7 @@ macro_rules! arena_types {
             [] dtorck_constraint: rustc_middle::traits::query::DropckConstraint<'tcx>,
             [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>,
             [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>,
-            [] canonical_goal_evaluation: rustc_middle::traits::solve::inspect::GoalEvaluationStep<'tcx>,
+            [] canonical_goal_evaluation: rustc_next_trait_solver::solve::inspect::GoalEvaluationStep<rustc_middle::ty::TyCtxt<'tcx>>,
             [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>,
             [] type_op_subtype:
                 rustc_middle::infer::canonical::Canonical<'tcx,
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index aee97d77222..49bf03e9c75 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -23,23 +23,20 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use rustc_type_ir::Canonical as IrCanonical;
-use rustc_type_ir::CanonicalVarInfo as IrCanonicalVarInfo;
+use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
+pub use rustc_type_ir as ir;
 pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind};
 use smallvec::SmallVec;
 use std::collections::hash_map::Entry;
-use std::ops::Index;
 
 use crate::infer::MemberConstraint;
 use crate::mir::ConstraintCategory;
 use crate::ty::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
-
-pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>;
-
-pub type CanonicalVarInfo<'tcx> = IrCanonicalVarInfo<TyCtxt<'tcx>>;
+use crate::ty::{self, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
 
+pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
+pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
+pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
 impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
@@ -51,74 +48,6 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
     }
 }
 
-/// A set of values corresponding to the canonical variables from some
-/// `Canonical`. You can give these values to
-/// `canonical_value.instantiate` to instantiate them into the canonical
-/// value at the right places.
-///
-/// When you canonicalize a value `V`, you get back one of these
-/// vectors with the original values that were replaced by canonical
-/// variables. You will need to supply it later to instantiate the
-/// canonicalized query response.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub struct CanonicalVarValues<'tcx> {
-    pub var_values: ty::GenericArgsRef<'tcx>,
-}
-
-impl CanonicalVarValues<'_> {
-    pub fn is_identity(&self) -> bool {
-        self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
-            ty::GenericArgKind::Lifetime(r) => {
-                matches!(*r, ty::ReBound(ty::INNERMOST, br) if br.var.as_usize() == bv)
-            }
-            ty::GenericArgKind::Type(ty) => {
-                matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
-            }
-            ty::GenericArgKind::Const(ct) => {
-                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
-            }
-        })
-    }
-
-    pub fn is_identity_modulo_regions(&self) -> bool {
-        let mut var = ty::BoundVar::ZERO;
-        for arg in self.var_values {
-            match arg.unpack() {
-                ty::GenericArgKind::Lifetime(r) => {
-                    if let ty::ReBound(ty::INNERMOST, br) = *r
-                        && var == br.var
-                    {
-                        var = var + 1;
-                    } else {
-                        // It's ok if this region var isn't unique
-                    }
-                }
-                ty::GenericArgKind::Type(ty) => {
-                    if let ty::Bound(ty::INNERMOST, bt) = *ty.kind()
-                        && var == bt.var
-                    {
-                        var = var + 1;
-                    } else {
-                        return false;
-                    }
-                }
-                ty::GenericArgKind::Const(ct) => {
-                    if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind()
-                        && var == bc
-                    {
-                        var = var + 1;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-        }
-
-        true
-    }
-}
-
 /// When we canonicalize a value to form a query, we wind up replacing
 /// various parts of it with canonical variables. This struct stores
 /// those replaced bits to remember for when we process the query
@@ -218,78 +147,6 @@ TrivialTypeTraversalImpls! {
     crate::infer::canonical::Certainty,
 }
 
-impl<'tcx> CanonicalVarValues<'tcx> {
-    // Given a list of canonical variables, construct a set of values which are
-    // the identity response.
-    pub fn make_identity(
-        tcx: TyCtxt<'tcx>,
-        infos: CanonicalVarInfos<'tcx>,
-    ) -> CanonicalVarValues<'tcx> {
-        CanonicalVarValues {
-            var_values: tcx.mk_args_from_iter(infos.iter().enumerate().map(
-                |(i, info)| -> ty::GenericArg<'tcx> {
-                    match info.kind {
-                        CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
-                            Ty::new_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i).into())
-                                .into()
-                        }
-                        CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
-                            let br = ty::BoundRegion {
-                                var: ty::BoundVar::from_usize(i),
-                                kind: ty::BrAnon,
-                            };
-                            ty::Region::new_bound(tcx, ty::INNERMOST, br).into()
-                        }
-                        CanonicalVarKind::Effect => ty::Const::new_bound(
-                            tcx,
-                            ty::INNERMOST,
-                            ty::BoundVar::from_usize(i),
-                            tcx.types.bool,
-                        )
-                        .into(),
-                        CanonicalVarKind::Const(_, ty)
-                        | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
-                            tcx,
-                            ty::INNERMOST,
-                            ty::BoundVar::from_usize(i),
-                            ty,
-                        )
-                        .into(),
-                    }
-                },
-            )),
-        }
-    }
-
-    /// Creates dummy var values which should not be used in a
-    /// canonical response.
-    pub fn dummy() -> CanonicalVarValues<'tcx> {
-        CanonicalVarValues { var_values: ty::List::empty() }
-    }
-
-    #[inline]
-    pub fn len(&self) -> usize {
-        self.var_values.len()
-    }
-}
-
-impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
-    type Item = GenericArg<'tcx>;
-    type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.var_values.iter()
-    }
-}
-
-impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
-    type Output = GenericArg<'tcx>;
-
-    fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
-        &self.var_values[value.as_usize()]
-    }
-}
-
 #[derive(Default)]
 pub struct CanonicalParamEnvCache<'tcx> {
     map: Lock<
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index fb796bf87a1..62e71c4db11 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -9,7 +9,6 @@ pub mod specialization_graph;
 mod structural_impls;
 pub mod util;
 
-use crate::infer::canonical::Canonical;
 use crate::mir::ConstraintCategory;
 use crate::ty::abstract_const::NotConstEvaluatable;
 use crate::ty::GenericArgsRef;
@@ -32,6 +31,8 @@ use std::borrow::Cow;
 use std::hash::{Hash, Hasher};
 
 pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
+// FIXME: Remove this import and import via `solve::`
+pub use rustc_next_trait_solver::solve::BuiltinImplSource;
 
 /// Depending on the stage of compilation, we want projection to be
 /// more or less conservative.
@@ -736,32 +737,6 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum BuiltinImplSource {
-    /// Some builtin impl we don't need to differentiate. This should be used
-    /// unless more specific information is necessary.
-    Misc,
-    /// A builtin impl for trait objects.
-    ///
-    /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits, pointers to supertrait vtable will
-    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
-    /// in that vtable.
-    Object { vtable_base: usize },
-    /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits, pointers to supertrait vtable will
-    /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
-    /// within that vtable.
-    TraitUpcasting { vtable_vptr_slot: Option<usize> },
-    /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
-    ///
-    /// This needs to be a separate variant as it is still unstable and we need to emit
-    /// a feature error when using it on stable.
-    TupleUnsizing,
-}
-
-TrivialTypeTraversalImpls! { BuiltinImplSource }
-
 #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
 pub enum ObjectSafetyViolation {
     /// `Self: Sized` declared on the trait.
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 70f3532e3ab..66e50307733 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -12,6 +12,8 @@ use crate::ty::GenericArg;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
+// FIXME: Remove this import and import via `traits::solve`.
+pub use rustc_next_trait_solver::solve::NoSolution;
 
 pub mod type_op {
     use crate::ty::fold::TypeFoldable;
@@ -89,9 +91,6 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
 pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
     Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
 
-#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)]
-pub struct NoSolution;
-
 impl<'tcx> From<TypeError<'tcx>> for NoSolution {
     fn from(_: TypeError<'tcx>) -> NoSolution {
         NoSolution
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 3ad6b68d129..c8c16ec1e2c 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -1,122 +1,24 @@
 use rustc_ast_ir::try_visit;
 use rustc_data_structures::intern::Interned;
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
-use rustc_span::def_id::DefId;
+use rustc_next_trait_solver as ir;
+pub use rustc_next_trait_solver::solve::*;
 
-use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
-use crate::traits::query::NoSolution;
-use crate::traits::Canonical;
+use crate::infer::canonical::QueryRegionConstraints;
 use crate::ty::{
-    self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
-    TypeVisitor,
+    self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
 };
 
-use super::BuiltinImplSource;
-
 mod cache;
-pub mod inspect;
 
 pub use cache::{CacheData, EvaluationCache};
 
-/// A goal is a statement, i.e. `predicate`, we want to prove
-/// given some assumptions, i.e. `param_env`.
-///
-/// Most of the time the `param_env` contains the `where`-bounds of the function
-/// we're currently typechecking while the `predicate` is some trait bound.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct Goal<'tcx, P> {
-    pub predicate: P,
-    pub param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'tcx, P> Goal<'tcx, P> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, P>,
-    ) -> Goal<'tcx, P> {
-        Goal { param_env, predicate: predicate.to_predicate(tcx) }
-    }
-
-    /// Updates the goal to one with a different `predicate` but the same `param_env`.
-    pub fn with<Q>(self, tcx: TyCtxt<'tcx>, predicate: impl ToPredicate<'tcx, Q>) -> Goal<'tcx, Q> {
-        Goal { param_env: self.param_env, predicate: predicate.to_predicate(tcx) }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct Response<'tcx> {
-    pub certainty: Certainty,
-    pub var_values: CanonicalVarValues<'tcx>,
-    /// Additional constraints returned by this query.
-    pub external_constraints: ExternalConstraints<'tcx>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum Certainty {
-    Yes,
-    Maybe(MaybeCause),
-}
-
-impl Certainty {
-    pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
-
-    /// Use this function to merge the certainty of multiple nested subgoals.
-    ///
-    /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested
-    /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`.
-    /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in
-    /// success, we merge these two responses. This results in ambiguity.
-    ///
-    /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
-    /// inside of the solver as we do not distinguish ambiguity from overflow. It does
-    /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
-    /// in ambiguity without changing the inference state, we still want to tell the
-    /// user that `T: Baz` results in overflow.
-    pub fn unify_with(self, other: Certainty) -> Certainty {
-        match (self, other) {
-            (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
-            (Certainty::Yes, Certainty::Maybe(_)) => other,
-            (Certainty::Maybe(_), Certainty::Yes) => self,
-            (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
-        }
-    }
-
-    pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
-        Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
-    }
-}
-
-/// Why we failed to evaluate a goal.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum MaybeCause {
-    /// We failed due to ambiguity. This ambiguity can either
-    /// be a true ambiguity, i.e. there are multiple different answers,
-    /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
-    Ambiguity,
-    /// We gave up due to an overflow, most often by hitting the recursion limit.
-    Overflow { suggest_increasing_limit: bool },
-}
-
-impl MaybeCause {
-    fn unify_with(self, other: MaybeCause) -> MaybeCause {
-        match (self, other) {
-            (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
-            (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
-            (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
-            (
-                MaybeCause::Overflow { suggest_increasing_limit: a },
-                MaybeCause::Overflow { suggest_increasing_limit: b },
-            ) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct QueryInput<'tcx, T> {
-    pub goal: Goal<'tcx, T>,
-    pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
-}
+pub type Goal<'tcx, P> = ir::solve::Goal<TyCtxt<'tcx>, P>;
+pub type QueryInput<'tcx, P> = ir::solve::QueryInput<TyCtxt<'tcx>, P>;
+pub type QueryResult<'tcx> = ir::solve::QueryResult<TyCtxt<'tcx>>;
+pub type CandidateSource<'tcx> = ir::solve::CandidateSource<TyCtxt<'tcx>>;
+pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput<TyCtxt<'tcx>, P>;
+pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse<TyCtxt<'tcx>>;
 
 /// Additional constraints returned on success.
 #[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
@@ -135,18 +37,6 @@ impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
     }
 }
 
-pub type CanonicalInput<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, QueryInput<'tcx, T>>;
-
-pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
-
-/// The result of evaluating a canonical query.
-///
-/// FIXME: We use a different type than the existing canonical queries. This is because
-/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
-/// having to worry about changes to currently used code. Once we've made progress on this
-/// solver, merge the two responses again.
-pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>;
-
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
 pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>);
 
@@ -253,91 +143,3 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
         self.opaque_types.visit_with(visitor)
     }
 }
-
-/// Why a specific goal has to be proven.
-///
-/// This is necessary as we treat nested goals different depending on
-/// their source.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeVisitable, TypeFoldable)]
-pub enum GoalSource {
-    Misc,
-    /// We're proving a where-bound of an impl.
-    ///
-    /// FIXME(-Znext-solver=coinductive): Explain how and why this
-    /// changes whether cycles are coinductive.
-    ///
-    /// This also impacts whether we erase constraints on overflow.
-    /// Erasing constraints is generally very useful for perf and also
-    /// results in better error messages by avoiding spurious errors.
-    /// We do not erase overflow constraints in `normalizes-to` goals unless
-    /// they are from an impl where-clause. This is necessary due to
-    /// backwards compatability, cc trait-system-refactor-initiatitive#70.
-    ImplWhereBound,
-    /// Instantiating a higher-ranked goal and re-proving it.
-    InstantiateHigherRanked,
-}
-
-/// Possible ways the given goal can be proven.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum CandidateSource {
-    /// A user written impl.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// fn main() {
-    ///     let x: Vec<u32> = Vec::new();
-    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
-    ///     let y = x.clone();
-    /// }
-    /// ```
-    Impl(DefId),
-    /// A builtin impl generated by the compiler. When adding a new special
-    /// trait, try to use actual impls whenever possible. Builtin impls should
-    /// only be used in cases where the impl cannot be manually be written.
-    ///
-    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
-    /// For a list of all traits with builtin impls, check out the
-    /// `EvalCtxt::assemble_builtin_impl_candidates` method.
-    BuiltinImpl(BuiltinImplSource),
-    /// An assumption from the environment.
-    ///
-    /// More precisely we've used the `n-th` assumption in the `param_env`.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// fn is_clone<T: Clone>(x: T) -> (T, T) {
-    ///     // This uses the assumption `T: Clone` from the `where`-bounds
-    ///     // to prove `T: Clone`.
-    ///     (x.clone(), x)
-    /// }
-    /// ```
-    ParamEnv(usize),
-    /// If the self type is an alias type, e.g. an opaque type or a projection,
-    /// we know the bounds on that alias to hold even without knowing its concrete
-    /// underlying type.
-    ///
-    /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
-    /// the self type.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// trait Trait {
-    ///     type Assoc: Clone;
-    /// }
-    ///
-    /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
-    ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
-    ///     // in the trait definition.
-    ///     let _y = x.clone();
-    /// }
-    /// ```
-    AliasBound,
-    /// A candidate that is registered only during coherence to represent some
-    /// yet-unknown impl that could be produced downstream without violating orphan
-    /// rules.
-    // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
-    CoherenceUnknowable,
-}
diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs
index 4f90af0a27c..03ce7cf98cf 100644
--- a/compiler/rustc_middle/src/traits/solve/cache.rs
+++ b/compiler/rustc_middle/src/traits/solve/cache.rs
@@ -17,7 +17,7 @@ pub struct EvaluationCache<'tcx> {
 #[derive(PartialEq, Eq)]
 pub struct CacheData<'tcx> {
     pub result: QueryResult<'tcx>,
-    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
+    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
     pub reached_depth: usize,
     pub encountered_overflow: bool,
 }
@@ -28,7 +28,7 @@ impl<'tcx> EvaluationCache<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         key: CanonicalInput<'tcx>,
-        proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
+        proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
         reached_depth: usize,
         encountered_overflow: bool,
         cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
@@ -105,7 +105,7 @@ struct Success<'tcx> {
 #[derive(Clone, Copy)]
 pub struct QueryData<'tcx> {
     pub result: QueryResult<'tcx>,
-    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
+    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
 }
 
 /// The cache entry for a goal `CanonicalInput`.
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
index 3419827a742..707e076921b 100644
--- a/compiler/rustc_middle/src/traits/util.rs
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashSet;
 
-use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, ToPredicate, TyCtxt};
+use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, TyCtxt, Upcast};
 
 /// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition.
 ///
@@ -11,7 +11,7 @@ pub fn super_predicates_for_pretty_printing<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: PolyTraitRef<'tcx>,
 ) -> impl Iterator<Item = Clause<'tcx>> {
-    let clause = trait_ref.to_predicate(tcx);
+    let clause = trait_ref.upcast(tcx);
     Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] }
 }
 
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 9badf65115e..6d7b6259747 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -15,7 +15,7 @@ pub enum PointerCoercion {
 
     /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
     /// It cannot convert a closure that requires unsafe.
-    ClosureFnPointer(hir::Unsafety),
+    ClosureFnPointer(hir::Safety),
 
     /// Go from a mut raw pointer to a const raw pointer.
     MutToConstPointer,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d7e185dd5e1..69681930be6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -89,20 +89,26 @@ use std::ops::{Bound, Deref};
 #[allow(rustc::usage_of_ty_tykind)]
 impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefId = DefId;
-    type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
     type AdtDef = ty::AdtDef<'tcx>;
+
     type GenericArgs = ty::GenericArgsRef<'tcx>;
-    type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
+    type OwnItemArgs = &'tcx [ty::GenericArg<'tcx>];
     type GenericArg = ty::GenericArg<'tcx>;
-
     type Term = ty::Term<'tcx>;
+
     type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
     type BoundVars = &'tcx List<ty::BoundVariableKind>;
     type BoundVar = ty::BoundVariableKind;
 
     type CanonicalVars = CanonicalVarInfos<'tcx>;
+    type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
+    type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
+    type ExternalConstraints = ExternalConstraints<'tcx>;
+    type GoalEvaluationSteps = &'tcx [solve::inspect::GoalEvaluationStep<TyCtxt<'tcx>>];
+
     type Ty = Ty<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
+    type FnInputTys = &'tcx [Ty<'tcx>];
     type ParamTy = ParamTy;
     type BoundTy = ty::BoundTy;
     type PlaceholderTy = ty::PlaceholderType;
@@ -113,21 +119,25 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type AllocId = crate::mir::interpret::AllocId;
 
     type Pat = Pattern<'tcx>;
+    type Safety = hir::Safety;
+    type Abi = abi::Abi;
+
     type Const = ty::Const<'tcx>;
     type AliasConst = ty::UnevaluatedConst<'tcx>;
     type PlaceholderConst = ty::PlaceholderConst;
     type ParamConst = ty::ParamConst;
     type BoundConst = ty::BoundVar;
     type ValueConst = ty::ValTree<'tcx>;
-
     type ExprConst = ty::Expr<'tcx>;
+
     type Region = Region<'tcx>;
     type EarlyParamRegion = ty::EarlyParamRegion;
     type LateParamRegion = ty::LateParamRegion;
     type BoundRegion = ty::BoundRegion;
     type InferRegion = ty::RegionVid;
-
     type PlaceholderRegion = ty::PlaceholderRegion;
+
+    type ParamEnv = ty::ParamEnv<'tcx>;
     type Predicate = Predicate<'tcx>;
     type TraitPredicate = ty::TraitPredicate<'tcx>;
     type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
@@ -135,10 +145,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
     type NormalizesTo = ty::NormalizesTo<'tcx>;
     type SubtypePredicate = ty::SubtypePredicate<'tcx>;
+
     type CoercePredicate = ty::CoercePredicate<'tcx>;
     type ClosureKind = ty::ClosureKind;
 
     type Clauses = ty::Clauses<'tcx>;
+
     fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
         self.mk_canonical_var_infos(infos)
     }
@@ -191,7 +203,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self,
         def_id: Self::DefId,
         args: Self::GenericArgs,
-    ) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
+    ) -> (rustc_type_ir::TraitRef<Self>, Self::OwnItemArgs) {
         assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
         let trait_def_id = self.parent(def_id);
         assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
@@ -223,6 +235,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     }
 }
 
+impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
+    fn is_rust(self) -> bool {
+        matches!(self, abi::Abi::Rust)
+    }
+}
+
+impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
+    fn prefix_str(self) -> &'static str {
+        self.prefix_str()
+    }
+}
+
 type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
 
 pub struct CtxtInterners<'tcx> {
@@ -2006,11 +2030,8 @@ impl<'tcx> TyCtxt<'tcx> {
     /// that is, a `fn` type that is equivalent in every way for being
     /// unsafe.
     pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
-        assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
-        Ty::new_fn_ptr(
-            self,
-            sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }),
-        )
+        assert_eq!(sig.safety(), hir::Safety::Safe);
+        Ty::new_fn_ptr(self, sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig }))
     }
 
     /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
@@ -2067,20 +2088,16 @@ impl<'tcx> TyCtxt<'tcx> {
     /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
     /// you would get a `fn(u32, i32)`.
     /// `unsafety` determines the unsafety of the fn signature. If you pass
-    /// `hir::Unsafety::Unsafe` in the previous example, then you would get
+    /// `hir::Safety::Unsafe` in the previous example, then you would get
     /// an `unsafe fn (u32, i32)`.
     /// It cannot convert a closure that requires unsafe.
-    pub fn signature_unclosure(
-        self,
-        sig: PolyFnSig<'tcx>,
-        unsafety: hir::Unsafety,
-    ) -> PolyFnSig<'tcx> {
+    pub fn signature_unclosure(self, sig: PolyFnSig<'tcx>, safety: hir::Safety) -> PolyFnSig<'tcx> {
         sig.map_bound(|s| {
             let params = match s.inputs()[0].kind() {
                 ty::Tuple(params) => *params,
                 _ => bug!(),
             };
-            self.mk_fn_sig(params, s.output(), s.c_variadic, unsafety, abi::Abi::Rust)
+            self.mk_fn_sig(params, s.output(), s.c_variadic, safety, abi::Abi::Rust)
         })
     }
 
@@ -2347,7 +2364,7 @@ impl<'tcx> TyCtxt<'tcx> {
         inputs: I,
         output: I::Item,
         c_variadic: bool,
-        unsafety: hir::Unsafety,
+        safety: hir::Safety,
         abi: abi::Abi,
     ) -> T::Output
     where
@@ -2357,7 +2374,7 @@ impl<'tcx> TyCtxt<'tcx> {
         T::collect_and_apply(inputs.into_iter().chain(iter::once(output)), |xs| ty::FnSig {
             inputs_and_output: self.mk_type_list(xs),
             c_variadic,
-            unsafety,
+            safety,
             abi,
         })
     }
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 71437ce1df9..99d703be873 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -34,7 +34,7 @@ pub enum TypeError<'tcx> {
     Mismatch,
     ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
     PolarityMismatch(ExpectedFound<ty::PredicatePolarity>),
-    UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
+    SafetyMismatch(ExpectedFound<hir::Safety>),
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
     ArgumentMutability(usize),
@@ -107,7 +107,7 @@ impl<'tcx> TypeError<'tcx> {
                 format!("expected {} polarity, found {} polarity", values.expected, values.found)
                     .into()
             }
-            UnsafetyMismatch(values) => {
+            SafetyMismatch(values) => {
                 format!("expected {} fn, found {} fn", values.expected, values.found).into()
             }
             AbiMismatch(values) => {
@@ -204,7 +204,7 @@ impl<'tcx> TypeError<'tcx> {
     pub fn must_include_note(self) -> bool {
         use self::TypeError::*;
         match self {
-            CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
+            CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_)
             | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
             | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
             | VariadicMismatch(_) | TargetFeatureCast(_) => false,
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 8d7489f5f7e..7508f0080cc 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -281,13 +281,13 @@ impl DeepRejectCtxt {
             }
             ty::FnPtr(obl_sig) => match k {
                 ty::FnPtr(impl_sig) => {
-                    let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } =
+                    let ty::FnSig { inputs_and_output, c_variadic, safety, abi } =
                         obl_sig.skip_binder();
                     let impl_sig = impl_sig.skip_binder();
 
                     abi == impl_sig.abi
                         && c_variadic == impl_sig.c_variadic
-                        && unsafety == impl_sig.unsafety
+                        && safety == impl_sig.safety
                         && inputs_and_output.len() == impl_sig.inputs_and_output.len()
                         && iter::zip(inputs_and_output, impl_sig.inputs_and_output)
                             .all(|(obl, imp)| self.types_may_unify(obl, imp))
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 904c0c332a8..38b2987399a 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -11,6 +11,7 @@ use rustc_ast_ir::walk_visitable_list;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir::def_id::DefId;
+use rustc_macros::extension;
 use rustc_macros::{
     Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
 };
@@ -25,6 +26,8 @@ use std::num::NonZero;
 use std::ops::Deref;
 use std::ptr::NonNull;
 
+pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>;
+
 /// An entity in the Rust type system, which can be one of
 /// several kinds (types, lifetimes, and consts).
 /// To reduce memory usage, a `GenericArg` is an interned pointer,
@@ -49,6 +52,14 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg
     }
 }
 
+impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> {
+    type Kind = GenericArgKind<'tcx>;
+
+    fn kind(self) -> Self::Kind {
+        self.unpack()
+    }
+}
+
 #[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where
     &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend
@@ -79,13 +90,7 @@ const TYPE_TAG: usize = 0b00;
 const REGION_TAG: usize = 0b01;
 const CONST_TAG: usize = 0b10;
 
-#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, HashStable)]
-pub enum GenericArgKind<'tcx> {
-    Lifetime(ty::Region<'tcx>),
-    Type(Ty<'tcx>),
-    Const(ty::Const<'tcx>),
-}
-
+#[extension(trait GenericArgPackExt<'tcx>)]
 impl<'tcx> GenericArgKind<'tcx> {
     #[inline]
     fn pack(self) -> GenericArg<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 93ccc0a7de4..ce63fc20ddb 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -28,7 +28,7 @@ use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::util::Discr;
 pub use adt::*;
 pub use assoc::*;
-pub use generic_args::*;
+pub use generic_args::{GenericArgKind, *};
 pub use generics::*;
 pub use intrinsic::IntrinsicDef;
 use rustc_ast as ast;
@@ -102,7 +102,7 @@ pub use self::predicate::{
     PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
     PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
     PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
-    ToPredicate, TraitPredicate, TraitRef, TypeOutlivesPredicate,
+    TraitPredicate, TraitRef, TypeOutlivesPredicate,
 };
 pub use self::region::{
     BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region,
@@ -266,7 +266,7 @@ pub struct ImplHeader<'tcx> {
 pub struct ImplTraitHeader<'tcx> {
     pub trait_ref: ty::EarlyBinder<ty::TraitRef<'tcx>>,
     pub polarity: ImplPolarity,
-    pub unsafety: hir::Unsafety,
+    pub safety: hir::Safety,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 16ca098853e..644fca7c5fe 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -9,7 +9,7 @@ use std::cmp::Ordering;
 
 use crate::ty::{
     self, Binder, DebruijnIndex, EarlyBinder, PredicatePolarity, Term, Ty, TyCtxt, TypeFlags,
-    WithCachedTypeInfo,
+    Upcast, UpcastFrom, WithCachedTypeInfo,
 };
 
 pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
@@ -234,10 +234,10 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
     pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> {
         match self.skip_binder() {
             ExistentialPredicate::Trait(tr) => {
-                self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx)
+                self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx)
             }
             ExistentialPredicate::Projection(p) => {
-                self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
+                self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx)
             }
             ExistentialPredicate::AutoTrait(did) => {
                 let generics = tcx.generics_of(did);
@@ -249,7 +249,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
                     let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
                     ty::TraitRef::new(tcx, did, err_args)
                 };
-                self.rebind(trait_ref).to_predicate(tcx)
+                self.rebind(trait_ref).upcast(tcx)
             }
         }
     }
@@ -544,185 +544,164 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
     }
 }
 
-pub trait ToPredicate<'tcx, P = Predicate<'tcx>> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P;
-}
-
-impl<'tcx, T> ToPredicate<'tcx, T> for T {
-    fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T {
-        self
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PredicateKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(from).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(self).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, PredicateKind<'tcx>>> for Predicate<'tcx> {
+    fn upcast_from(from: Binder<'tcx, PredicateKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(from)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(self)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: ClauseKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(ty::Binder::dummy(PredicateKind::Clause(from)))
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self)))
-    }
-}
-
-impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause))
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, ClauseKind<'tcx>>> for Predicate<'tcx> {
+    fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(from.map_bound(PredicateKind::Clause))
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.as_predicate()
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Clause<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: Clause<'tcx>, _tcx: TyCtxt<'tcx>) -> Self {
+        from.as_predicate()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause()
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: ClauseKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(from))).expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause()
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, ClauseKind<'tcx>>> for Clause<'tcx> {
+    fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(from.map_bound(|clause| PredicateKind::Clause(clause))).expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(self).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(from).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> {
-        TraitPredicate { trait_ref: self, polarity: PredicatePolarity::Positive }
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for TraitPredicate<'tcx> {
+    fn upcast_from(from: TraitRef<'tcx>, _tcx: TyCtxt<'tcx>) -> Self {
+        TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive }
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
-        pred.to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for Predicate<'tcx> {
+    fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx);
+        pred.upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
-        pred.to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for Clause<'tcx> {
+    fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx);
+        pred.upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
-        self.map_bound(|trait_ref| TraitPredicate {
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> {
+    fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|trait_ref| TraitPredicate {
             trait_ref,
-            polarity: ty::PredicatePolarity::Positive,
+            polarity: PredicatePolarity::Positive,
         })
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: TraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        PredicateKind::Clause(ClauseKind::Trait(from)).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyTraitPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PolyTraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: TraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyTraitPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: PolyTraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyRegionOutlivesPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(self))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>
+    for Predicate<'tcx>
+{
+    fn upcast_from(from: OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(from))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ProjectionPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: ProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(from))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyProjectionPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PolyProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ProjectionPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: ProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyProjectionPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: PolyProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for NormalizesTo<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        PredicateKind::NormalizesTo(self).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, NormalizesTo<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: NormalizesTo<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        PredicateKind::NormalizesTo(from).upcast(tcx)
     }
 }
 
 impl<'tcx> Predicate<'tcx> {
-    pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
+    pub fn as_trait_clause(self) -> Option<PolyTraitPredicate<'tcx>> {
         let predicate = self.kind();
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
@@ -742,7 +721,7 @@ impl<'tcx> Predicate<'tcx> {
         }
     }
 
-    pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> {
+    pub fn as_projection_clause(self) -> Option<PolyProjectionPredicate<'tcx>> {
         let predicate = self.kind();
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 3577db7234d..0dbb17e9db4 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3034,6 +3034,16 @@ forward_display_to_print! {
 define_print! {
     (self, cx):
 
+    ty::FnSig<'tcx> {
+        p!(write("{}", self.safety.prefix_str()));
+
+        if self.abi != Abi::Rust {
+            p!(write("extern {} ", self.abi));
+        }
+
+        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
+    }
+
     ty::TraitRef<'tcx> {
         p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
     }
@@ -3169,16 +3179,6 @@ define_print_and_forward_display! {
         p!("{{", comma_sep(self.iter()), "}}")
     }
 
-    ty::FnSig<'tcx> {
-        p!(write("{}", self.unsafety.prefix_str()));
-
-        if self.abi != Abi::Rust {
-            p!(write("extern {} ", self.abi));
-        }
-
-        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
-    }
-
     TraitRefPrintOnlyTraitPath<'tcx> {
         p!(print_def_path(self.0.def_id, self.0.args));
     }
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 8842ecd12e9..7540f0ab83f 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -396,6 +396,12 @@ pub struct BoundRegion {
     pub kind: BoundRegionKind,
 }
 
+impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundRegion {
+    fn var(self) -> BoundVar {
+        self.var
+    }
+}
+
 impl core::fmt::Debug for BoundRegion {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self.kind {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index eaf5fdf5710..947de3f3aaa 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -146,7 +146,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
         if a.c_variadic != b.c_variadic {
             return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic)));
         }
-        let unsafety = relation.relate(a.unsafety, b.unsafety)?;
+        let safety = relation.relate(a.safety, b.safety)?;
         let abi = relation.relate(a.abi, b.abi)?;
 
         if a.inputs().len() != b.inputs().len() {
@@ -181,7 +181,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
         Ok(ty::FnSig {
             inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?,
             c_variadic: a.c_variadic,
-            unsafety,
+            safety,
             abi,
         })
     }
@@ -197,13 +197,13 @@ impl<'tcx> Relate<'tcx> for ty::BoundConstness {
     }
 }
 
-impl<'tcx> Relate<'tcx> for hir::Unsafety {
+impl<'tcx> Relate<'tcx> for hir::Safety {
     fn relate<R: TypeRelation<'tcx>>(
         _relation: &mut R,
-        a: hir::Unsafety,
-        b: hir::Unsafety,
-    ) -> RelateResult<'tcx, hir::Unsafety> {
-        if a != b { Err(TypeError::UnsafetyMismatch(expected_found(a, b))) } else { Ok(a) }
+        a: hir::Safety,
+        b: hir::Safety,
+    ) -> RelateResult<'tcx, hir::Safety> {
+        if a != b { Err(TypeError::SafetyMismatch(expected_found(a, b))) } else { Ok(a) }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7523cd15320..7d24824d568 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -83,49 +83,6 @@ impl fmt::Debug for ty::LateParamRegion {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        let sig = this.data;
-        let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig;
-
-        write!(f, "{}", unsafety.prefix_str())?;
-        match abi {
-            rustc_target::spec::abi::Abi::Rust => (),
-            abi => write!(f, "extern \"{abi:?}\" ")?,
-        };
-
-        write!(f, "fn(")?;
-        let inputs = sig.inputs();
-        match inputs.len() {
-            0 if *c_variadic => write!(f, "...)")?,
-            0 => write!(f, ")")?,
-            _ => {
-                for ty in &sig.inputs()[0..(sig.inputs().len() - 1)] {
-                    write!(f, "{:?}, ", &this.wrap(ty))?;
-                }
-                write!(f, "{:?}", &this.wrap(sig.inputs().last().unwrap()))?;
-                if *c_variadic {
-                    write!(f, "...")?;
-                }
-                write!(f, ")")?;
-            }
-        }
-
-        match sig.output().kind() {
-            ty::Tuple(list) if list.is_empty() => Ok(()),
-            _ => write!(f, " -> {:?}", &this.wrap(sig.output())),
-        }
-    }
-}
-
 impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
     fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
         this: WithInfcx<'_, Infcx, &Self>,
@@ -398,7 +355,7 @@ TrivialTypeTraversalImpls! {
 // interners).
 TrivialTypeTraversalAndLiftImpls! {
     ::rustc_hir::def_id::DefId,
-    ::rustc_hir::Unsafety,
+    ::rustc_hir::Safety,
     ::rustc_target::spec::abi::Abi,
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 74b03d6db66..7c41c5f512e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -39,6 +39,7 @@ use super::GenericParamDefKind;
 pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
 pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
 pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
+pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
 
 pub trait Article {
     fn article(&self) -> &'static str;
@@ -387,7 +388,7 @@ impl<'tcx> CoroutineClosureArgs<'tcx> {
                 yield_ty,
                 return_ty,
                 c_variadic: sig.c_variadic,
-                unsafety: sig.unsafety,
+                safety: sig.safety,
                 abi: sig.abi,
             }
         })
@@ -415,8 +416,8 @@ pub struct CoroutineClosureSignature<'tcx> {
     // from scratch just for good measure.
     /// Always false
     pub c_variadic: bool,
-    /// Always [`hir::Unsafety::Normal`]
-    pub unsafety: hir::Unsafety,
+    /// Always [`hir::Safety::Safe`]
+    pub safety: hir::Safety,
     /// Always [`abi::Abi::RustCall`]
     pub abi: abi::Abi,
 }
@@ -985,14 +986,6 @@ impl<'tcx, T> Binder<'tcx, T> {
         Binder { value: &self.value, bound_vars: self.bound_vars }
     }
 
-    pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U>
-    where
-        F: FnOnce(&T) -> U,
-    {
-        let value = f(&self.value);
-        Binder { value, bound_vars: self.bound_vars }
-    }
-
     pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U>
     where
         F: FnOnce(&T) -> U,
@@ -1109,73 +1102,37 @@ pub struct GenSig<'tcx> {
     pub return_ty: Ty<'tcx>,
 }
 
-/// Signature of a function type, which we have arbitrarily
-/// decided to use to refer to the input/output types.
-///
-/// - `inputs`: is the list of arguments and their modes.
-/// - `output`: is the return type.
-/// - `c_variadic`: indicates whether this is a C-variadic function.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct FnSig<'tcx> {
-    pub inputs_and_output: &'tcx List<Ty<'tcx>>,
-    pub c_variadic: bool,
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-}
-
-impl<'tcx> FnSig<'tcx> {
-    pub fn inputs(&self) -> &'tcx [Ty<'tcx>] {
-        &self.inputs_and_output[..self.inputs_and_output.len() - 1]
-    }
-
-    pub fn output(&self) -> Ty<'tcx> {
-        self.inputs_and_output[self.inputs_and_output.len() - 1]
-    }
-
-    // Creates a minimal `FnSig` to be used when encountering a `TyKind::Error` in a fallible
-    // method.
-    fn fake() -> FnSig<'tcx> {
-        FnSig {
-            inputs_and_output: List::empty(),
-            c_variadic: false,
-            unsafety: hir::Unsafety::Normal,
-            abi: abi::Abi::Rust,
-        }
-    }
-}
-
-impl<'tcx> IntoDiagArg for FnSig<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.to_string().into_diag_arg()
-    }
-}
-
 pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>;
 
 impl<'tcx> PolyFnSig<'tcx> {
     #[inline]
     pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> {
-        self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs())
+        self.map_bound_ref(|fn_sig| fn_sig.inputs())
     }
+
     #[inline]
     #[track_caller]
     pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> {
         self.map_bound_ref(|fn_sig| fn_sig.inputs()[index])
     }
+
     pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> {
         self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
     }
+
     #[inline]
     pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
         self.map_bound_ref(|fn_sig| fn_sig.output())
     }
+
     pub fn c_variadic(&self) -> bool {
         self.skip_binder().c_variadic
     }
-    pub fn unsafety(&self) -> hir::Unsafety {
-        self.skip_binder().unsafety
+
+    pub fn safety(&self) -> hir::Safety {
+        self.skip_binder().safety
     }
+
     pub fn abi(&self) -> abi::Abi {
         self.skip_binder().abi
     }
@@ -1183,12 +1140,7 @@ impl<'tcx> PolyFnSig<'tcx> {
     pub fn is_fn_trait_compatible(&self) -> bool {
         matches!(
             self.skip_binder(),
-            ty::FnSig {
-                unsafety: rustc_hir::Unsafety::Normal,
-                abi: Abi::Rust,
-                c_variadic: false,
-                ..
-            }
+            ty::FnSig { safety: rustc_hir::Safety::Safe, abi: Abi::Rust, c_variadic: false, .. }
         )
     }
 }
@@ -1247,6 +1199,12 @@ pub struct BoundTy {
     pub kind: BoundTyKind,
 }
 
+impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundTy {
+    fn var(self) -> BoundVar {
+        self.var
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum BoundTyKind {
@@ -1649,6 +1607,10 @@ impl<'tcx> Ty<'tcx> {
 }
 
 impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
+    fn new_bool(tcx: TyCtxt<'tcx>) -> Self {
+        tcx.types.bool
+    }
+
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
     }
@@ -2031,7 +1993,12 @@ impl<'tcx> Ty<'tcx> {
             FnPtr(f) => *f,
             Error(_) => {
                 // ignore errors (#54954)
-                ty::Binder::dummy(FnSig::fake())
+                ty::Binder::dummy(ty::FnSig {
+                    inputs_and_output: ty::List::empty(),
+                    c_variadic: false,
+                    safety: hir::Safety::Safe,
+                    abi: abi::Abi::Rust,
+                })
             }
             Closure(..) => bug!(
                 "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
@@ -2624,6 +2591,13 @@ impl<'tcx> Ty<'tcx> {
     }
 }
 
+impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
+    fn split_inputs_and_output(self) -> (&'tcx [Ty<'tcx>], Ty<'tcx>) {
+        let (output, inputs) = self.split_last().unwrap();
+        (inputs, *output)
+    }
+}
+
 /// Extra information about why we ended up with a particular variance.
 /// This is only used to add more information to error messages, and
 /// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index cf5decffea9..c5b3de17bcb 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -15,7 +15,7 @@ use rustc_macros::{Decodable, Encodable, HashStable};
 pub struct TraitDef {
     pub def_id: DefId,
 
-    pub unsafety: hir::Unsafety,
+    pub safety: hir::Safety,
 
     /// If `true`, then this trait had the `#[rustc_paren_sugar]`
     /// attribute, indicating that it should be used with `Foo()`
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 7f3d6a713d9..8c14f1e080a 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -4,8 +4,8 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::query::{IntoQueryParam, Providers};
 use crate::ty::layout::{FloatExt, IntegerExt};
 use crate::ty::{
-    self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt,
+    self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, Upcast,
 };
 use crate::ty::{GenericArgKind, GenericArgsRef};
 use rustc_apfloat::Float as _;
@@ -1094,7 +1094,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
                     // anything that requires `ParamEnv::with_reveal_all_normalized`.
                     term: projection_pred.term,
                 })
-                .to_predicate(self.tcx)
+                .upcast(self.tcx)
         } else {
             p.super_fold_with(self)
         }
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index e3866b27cee..79f36cfe569 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -65,7 +65,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
             std::iter::repeat(err).take(arity),
             err,
             false,
-            rustc_hir::Unsafety::Normal,
+            rustc_hir::Safety::Safe,
             rustc_target::spec::abi::Abi::Rust,
         ));
 
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index b9990d65ec7..b5f7ffbd2af 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -391,7 +391,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 return; // don't visit the whole expression
             }
             ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
-                if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
+                if self.thir[fun].ty.fn_sig(self.tcx).safety() == hir::Safety::Unsafe {
                     let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
                         Some(*func_id)
                     } else {
@@ -921,7 +921,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
 
     let hir_id = tcx.local_def_id_to_hir_id(def);
     let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
-        if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
+        if fn_sig.header.safety == hir::Safety::Unsafe {
             SafetyContext::UnsafeFn
         } else {
             SafetyContext::Safe
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 30b1ca67800..434529ccff4 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -158,7 +158,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
             .lint_root;
         // FIXME: use existing printing routines to print the function signature
         let fn_sig = self.tcx.fn_sig(fn_id).instantiate(self.tcx, fn_args);
-        let unsafety = fn_sig.unsafety().prefix_str();
+        let unsafety = fn_sig.safety().prefix_str();
         let abi = match fn_sig.abi() {
             Abi::Rust => String::from(""),
             other_abi => {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index cd8a43d6e6c..dcf54ad2cfc 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -1047,7 +1047,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
                 args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
             ),
             sig.c_variadic,
-            sig.unsafety,
+            sig.safety,
             sig.abi,
         )
     });
diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml
index 9d496fd8e81..8bcc21d82f8 100644
--- a/compiler/rustc_next_trait_solver/Cargo.toml
+++ b/compiler/rustc_next_trait_solver/Cargo.toml
@@ -5,9 +5,19 @@ edition = "2021"
 
 [dependencies]
 rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
+derivative = "2.2.0"
+rustc_macros = { path = "../rustc_macros", optional = true }
+rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
+rustc_serialize = { path = "../rustc_serialize", optional = true }
+rustc_data_structures = { path = "../rustc_data_structures", optional = true }
+rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
 
 [features]
 default = ["nightly"]
 nightly = [
     "rustc_type_ir/nightly",
-]
\ No newline at end of file
+    "rustc_macros",
+    "rustc_serialize",
+    "rustc_data_structures",
+    "rustc_ast_ir/nightly",
+]
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs
index e5fc8f755e0..4202dc39fb2 100644
--- a/compiler/rustc_next_trait_solver/src/lib.rs
+++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -1 +1,2 @@
 pub mod canonicalizer;
+pub mod solve;
diff --git a/compiler/rustc_next_trait_solver/src/solve.rs b/compiler/rustc_next_trait_solver/src/solve.rs
new file mode 100644
index 00000000000..eba96facabc
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/solve.rs
@@ -0,0 +1 @@
+pub use rustc_type_ir::solve::*;
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 3e1be6461eb..a46c104b6d9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -33,7 +33,7 @@ impl<'a> Parser<'a> {
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
     fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety(Case::Sensitive);
+        let safety = self.parse_safety(Case::Sensitive);
         self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
         let mod_kind = if self.eat(&token::Semi) {
@@ -45,7 +45,7 @@ impl<'a> Parser<'a> {
             attrs.extend(inner_attrs);
             ModKind::Loaded(items, Inline::Yes, inner_span)
         };
-        Ok((id, ItemKind::Mod(unsafety, mod_kind)))
+        Ok((id, ItemKind::Mod(safety, mod_kind)))
     }
 
     /// Parses the contents of a module (inner attributes followed by module items).
@@ -211,13 +211,13 @@ impl<'a> Parser<'a> {
                 self.parse_item_extern_crate()?
             } else {
                 // EXTERN BLOCK
-                self.parse_item_foreign_mod(attrs, Unsafe::No)?
+                self.parse_item_foreign_mod(attrs, Safety::Default)?
             }
         } else if self.is_unsafe_foreign_mod() {
             // EXTERN BLOCK
-            let unsafety = self.parse_unsafety(Case::Sensitive);
+            let safety = self.parse_safety(Case::Sensitive);
             self.expect_keyword(kw::Extern)?;
-            self.parse_item_foreign_mod(attrs, unsafety)?
+            self.parse_item_foreign_mod(attrs, safety)?
         } else if self.is_static_global() {
             // STATIC ITEM
             self.bump(); // `static`
@@ -541,7 +541,7 @@ impl<'a> Parser<'a> {
         attrs: &mut AttrVec,
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety(Case::Sensitive);
+        let safety = self.parse_safety(Case::Sensitive);
         self.expect_keyword(kw::Impl)?;
 
         // First, parse generic parameters if necessary.
@@ -647,7 +647,7 @@ impl<'a> Parser<'a> {
                 let trait_ref = TraitRef { path, ref_id: ty_first.id };
 
                 ItemKind::Impl(Box::new(Impl {
-                    unsafety,
+                    safety,
                     polarity,
                     defaultness,
                     constness,
@@ -660,7 +660,7 @@ impl<'a> Parser<'a> {
             None => {
                 // impl Type
                 ItemKind::Impl(Box::new(Impl {
-                    unsafety,
+                    safety,
                     polarity,
                     defaultness,
                     constness,
@@ -865,7 +865,7 @@ impl<'a> Parser<'a> {
 
     /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
     fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety(Case::Sensitive);
+        let safety = self.parse_safety(Case::Sensitive);
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(kw::Auto) {
             self.psess.gated_spans.gate(sym::auto_traits, self.prev_token.span);
@@ -899,7 +899,7 @@ impl<'a> Parser<'a> {
             if is_auto == IsAuto::Yes {
                 self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });
             }
-            if let Unsafe::Yes(_) = unsafety {
+            if let Safety::Unsafe(_) = safety {
                 self.dcx().emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span });
             }
 
@@ -912,7 +912,7 @@ impl<'a> Parser<'a> {
             let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;
             Ok((
                 ident,
-                ItemKind::Trait(Box::new(Trait { is_auto, unsafety, generics, bounds, items })),
+                ItemKind::Trait(Box::new(Trait { is_auto, safety, generics, bounds, items })),
             ))
         }
     }
@@ -1173,19 +1173,19 @@ impl<'a> Parser<'a> {
     fn parse_item_foreign_mod(
         &mut self,
         attrs: &mut AttrVec,
-        mut unsafety: Unsafe,
+        mut safety: Safety,
     ) -> PResult<'a, ItemInfo> {
         let abi = self.parse_abi(); // ABI?
-        if unsafety == Unsafe::No
+        if safety == Safety::Default
             && self.token.is_keyword(kw::Unsafe)
             && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
         {
             self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit();
-            unsafety = Unsafe::Yes(self.token.span);
+            safety = Safety::Unsafe(self.token.span);
             self.eat_keyword(kw::Unsafe);
         }
         let module = ast::ForeignMod {
-            unsafety,
+            safety,
             abi,
             items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?,
         };
@@ -2452,7 +2452,7 @@ impl<'a> Parser<'a> {
         let coroutine_kind = self.parse_coroutine_kind(case);
 
         let unsafe_start_sp = self.token.span;
-        let unsafety = self.parse_unsafety(case);
+        let safety = self.parse_safety(case);
 
         let ext_start_sp = self.token.span;
         let ext = self.parse_extern(case);
@@ -2490,7 +2490,7 @@ impl<'a> Parser<'a> {
                     // We may be able to recover
                     let mut recover_constness = constness;
                     let mut recover_coroutine_kind = coroutine_kind;
-                    let mut recover_unsafety = unsafety;
+                    let mut recover_safety = safety;
                     // This will allow the machine fix to directly place the keyword in the correct place or to indicate
                     // that the keyword is already present and the second instance should be removed.
                     let wrong_kw = if self.check_keyword(kw::Const) {
@@ -2528,10 +2528,10 @@ impl<'a> Parser<'a> {
                             }
                         }
                     } else if self.check_keyword(kw::Unsafe) {
-                        match unsafety {
-                            Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)),
-                            Unsafe::No => {
-                                recover_unsafety = Unsafe::Yes(self.token.span);
+                        match safety {
+                            Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)),
+                            Safety::Default => {
+                                recover_safety = Safety::Unsafe(self.token.span);
                                 Some(WrongKw::Misplaced(ext_start_sp))
                             }
                         }
@@ -2616,7 +2616,7 @@ impl<'a> Parser<'a> {
                         err.emit();
                         return Ok(FnHeader {
                             constness: recover_constness,
-                            unsafety: recover_unsafety,
+                            safety: recover_safety,
                             coroutine_kind: recover_coroutine_kind,
                             ext,
                         });
@@ -2627,7 +2627,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        Ok(FnHeader { constness, unsafety, coroutine_kind, ext })
+        Ok(FnHeader { constness, safety, coroutine_kind, ext })
     }
 
     /// Parses the parameter list and result type of a function declaration.
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 3e0a98a55ae..c2183258eef 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -26,7 +26,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
 use rustc_ast::{
     self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs,
-    Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, StrLit, Unsafe, Visibility,
+    Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility,
     VisibilityKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust;
@@ -1217,12 +1217,12 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parses unsafety: `unsafe` or nothing.
-    fn parse_unsafety(&mut self, case: Case) -> Unsafe {
+    /// Parses fn unsafety: `unsafe`, `safe` or nothing.
+    fn parse_safety(&mut self, case: Case) -> Safety {
         if self.eat_keyword_case(kw::Unsafe, case) {
-            Unsafe::Yes(self.prev_token.uninterpolated_span())
+            Safety::Unsafe(self.prev_token.uninterpolated_span())
         } else {
-            Unsafe::No
+            Safety::Default
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index a6f0ab78b5c..619c4c63e51 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -36,13 +36,19 @@ impl<'a> Parser<'a> {
         }
 
         match kind {
-            NonterminalKind::Expr => {
+            NonterminalKind::Expr2021 => {
                 token.can_begin_expr()
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Let)
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Const)
             }
+            NonterminalKind::Expr => {
+                token.can_begin_expr()
+                // This exception is here for backwards compatibility.
+                && !token.is_keyword(kw::Let)
+                && (token.span.edition().at_least_rust_2024() || !token.is_keyword(kw::Const))
+            }
             NonterminalKind::Ty => token.can_begin_type(),
             NonterminalKind::Ident => get_macro_ident(token).is_some(),
             NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
@@ -143,7 +149,9 @@ impl<'a> Parser<'a> {
                 })?)
             }
 
-            NonterminalKind::Expr => NtExpr(self.parse_expr_force_collect()?),
+            NonterminalKind::Expr | NonterminalKind::Expr2021 => {
+                NtExpr(self.parse_expr_force_collect()?)
+            }
             NonterminalKind::Literal => {
                 // The `:literal` matcher does not support attributes
                 NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 2f08a48c7bc..2df8f58507b 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -590,7 +590,7 @@ impl<'a> Parser<'a> {
             tokens: None,
         };
         let span_start = self.token.span;
-        let ast::FnHeader { ext, unsafety, constness, coroutine_kind } =
+        let ast::FnHeader { ext, safety, constness, coroutine_kind } =
             self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
         if self.may_recover() && self.token.kind == TokenKind::Lt {
             self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
@@ -608,7 +608,7 @@ impl<'a> Parser<'a> {
         }
         // FIXME(gen_blocks): emit a similar error for `gen fn()`
         let decl_span = span_start.to(self.token.span);
-        Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, decl_span })))
+        Ok(TyKind::BareFn(P(BareFnTy { ext, safety, generic_params: params, decl, decl_span })))
     }
 
     /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`).
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index e60aa27dba2..aadbd747313 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -17,7 +17,7 @@ use rustc_hir::{self as hir};
 use rustc_hir::{
     self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
 };
-use rustc_hir::{MethodKind, Target, Unsafety};
+use rustc_hir::{MethodKind, Safety, Target};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
@@ -2335,7 +2335,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }),
             token_stream,
             false,
-            Unsafety::Normal,
+            Safety::Safe,
             Abi::Rust,
         );
 
@@ -2362,7 +2362,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             cause.span = ty.span;
                         }
                     }
-                    TypeError::UnsafetyMismatch(_) => {
+                    TypeError::SafetyMismatch(_) => {
                         // FIXME: Would be nice if we had a span here..
                     }
                     TypeError::AbiMismatch(_) => {
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 3e9aa3e0a6f..689109b2840 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -32,6 +32,8 @@ use rustc_span::Span;
 
 use std::cell::Cell;
 
+use tracing::debug;
+
 type Res = def::Res<NodeId>;
 
 impl<'a, Id: Into<DefId>> ToNameBinding<'a>
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 741a650da55..bd062242856 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -7,6 +7,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_span::hygiene::LocalExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
+use tracing::debug;
 
 pub(crate) fn collect_definitions(
     resolver: &mut Resolver<'_, '_>,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 01e279b6d04..b28312fa473 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -28,6 +28,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
 use thin_vec::{thin_vec, ThinVec};
+use tracing::debug;
 
 use crate::errors::{
     self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
@@ -43,9 +44,6 @@ use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, Vis
 use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet};
 use crate::{Segment, UseError};
 
-#[cfg(test)]
-mod tests;
-
 type Res = def::Res<ast::NodeId>;
 
 /// A vector of spans and replacements, a message and applicability.
@@ -3026,14 +3024,3 @@ fn is_span_suitable_for_use_injection(s: Span) -> bool {
     // import or other generated ones
     !s.from_expansion()
 }
-
-/// Convert the given number into the corresponding ordinal
-pub(crate) fn ordinalize(v: usize) -> String {
-    let suffix = match ((11..=13).contains(&(v % 100)), v % 10) {
-        (false, 1) => "st",
-        (false, 2) => "nd",
-        (false, 3) => "rd",
-        _ => "th",
-    };
-    format!("{v}{suffix}")
-}
diff --git a/compiler/rustc_resolve/src/diagnostics/tests.rs b/compiler/rustc_resolve/src/diagnostics/tests.rs
deleted file mode 100644
index 2aa6cc61e46..00000000000
--- a/compiler/rustc_resolve/src/diagnostics/tests.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use super::ordinalize;
-
-#[test]
-fn test_ordinalize() {
-    assert_eq!(ordinalize(1), "1st");
-    assert_eq!(ordinalize(2), "2nd");
-    assert_eq!(ordinalize(3), "3rd");
-    assert_eq!(ordinalize(4), "4th");
-    assert_eq!(ordinalize(5), "5th");
-    // ...
-    assert_eq!(ordinalize(10), "10th");
-    assert_eq!(ordinalize(11), "11th");
-    assert_eq!(ordinalize(12), "12th");
-    assert_eq!(ordinalize(13), "13th");
-    assert_eq!(ordinalize(14), "14th");
-    // ...
-    assert_eq!(ordinalize(20), "20th");
-    assert_eq!(ordinalize(21), "21st");
-    assert_eq!(ordinalize(22), "22nd");
-    assert_eq!(ordinalize(23), "23rd");
-    assert_eq!(ordinalize(24), "24th");
-    // ...
-    assert_eq!(ordinalize(30), "30th");
-    assert_eq!(ordinalize(31), "31st");
-    assert_eq!(ordinalize(32), "32nd");
-    assert_eq!(ordinalize(33), "33rd");
-    assert_eq!(ordinalize(34), "34th");
-    // ...
-    assert_eq!(ordinalize(7010), "7010th");
-    assert_eq!(ordinalize(7011), "7011th");
-    assert_eq!(ordinalize(7012), "7012th");
-    assert_eq!(ordinalize(7013), "7013th");
-    assert_eq!(ordinalize(7014), "7014th");
-    // ...
-    assert_eq!(ordinalize(7020), "7020th");
-    assert_eq!(ordinalize(7021), "7021st");
-    assert_eq!(ordinalize(7022), "7022nd");
-    assert_eq!(ordinalize(7023), "7023rd");
-    assert_eq!(ordinalize(7024), "7024th");
-}
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 074bf810eaf..aab4a3366da 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -11,6 +11,7 @@ use rustc_middle::middle::privacy::Level;
 use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility};
 use rustc_middle::ty::Visibility;
 use std::mem;
+use tracing::info;
 
 #[derive(Clone, Copy)]
 enum ParentId<'a> {
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 43a43e01a9a..f88725830f1 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -11,6 +11,7 @@ use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContex
 use rustc_span::sym;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
+use tracing::{debug, instrument};
 
 use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
 use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 3d9380a3ebd..f53bcb0e9d0 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -34,6 +34,7 @@ use rustc_span::hygiene::LocalExpnId;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 use smallvec::SmallVec;
+use tracing::debug;
 
 use std::cell::Cell;
 use std::mem;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 322f2922f92..0f585aafdd5 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -30,6 +30,7 @@ use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
 use smallvec::{smallvec, SmallVec};
+use tracing::{debug, instrument, trace};
 
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 12815291c1d..1958fdf1cbc 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -40,6 +40,7 @@ use std::iter;
 use std::ops::Deref;
 
 use thin_vec::ThinVec;
+use tracing::debug;
 
 use super::NoConstantGenericsReason;
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index af0b4792136..01bcfec4bdc 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -6,9 +6,13 @@
 //!
 //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
 
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::diagnostic_outside_of_impl)]
+#![allow(rustc::potential_query_instability)]
+#![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(rustdoc_internals)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(extract_if)]
@@ -16,18 +20,9 @@
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(rustc_attrs)]
-#![allow(rustdoc::private_intra_doc_links)]
-#![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::potential_query_instability)]
-#![allow(rustc::untranslatable_diagnostic)]
-#![allow(internal_features)]
-
-#[macro_use]
-extern crate tracing;
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
 
-use errors::{
-    ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
-};
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
@@ -60,19 +55,21 @@ use rustc_session::lint::LintBuffer;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-
 use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
 use std::fmt;
+use tracing::debug;
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
+use effective_visibilities::EffectiveVisibilitiesVisitor;
+use errors::{
+    ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
+};
 use imports::{Import, ImportData, ImportKind, NameResolution};
 use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 
-use crate::effective_visibilities::EffectiveVisibilitiesVisitor;
-
 type Res = def::Res<NodeId>;
 
 mod build_reduced_graph;
@@ -964,7 +961,6 @@ struct DeriveData {
     has_derive_copy: bool,
 }
 
-#[derive(Clone)]
 struct MacroData {
     ext: Lrc<SyntaxExtension>,
     rule_spans: Vec<(usize, Span)>,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index e3cfe6a6e05..f8d245f94e5 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -328,11 +328,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
                 UNUSED_MACRO_RULES,
                 node_id,
                 rule_span,
-                format!(
-                    "{} rule of macro `{}` is never used",
-                    crate::diagnostics::ordinalize(arm_i + 1),
-                    ident.name
-                ),
+                format!("rule #{} of macro `{}` is never used", arm_i + 1, ident.name),
             );
         }
     }
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index aace0f3fef9..66b4981eb55 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -8,6 +8,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use std::mem;
 use std::ops::Range;
+use tracing::{debug, trace};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum DocFragmentKind {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index f2bdabbf394..7dd9fdf60f9 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -798,6 +798,7 @@ pub enum DumpSolverProofTree {
     Never,
 }
 
+#[derive(Clone)]
 pub enum Input {
     /// Load source code from a file.
     File(PathBuf),
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 0893bc31bfa..6b73c1ebd1c 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -216,7 +216,7 @@ impl RustcInternal for FnSig {
         tcx.lift(rustc_ty::FnSig {
             inputs_and_output: tcx.mk_type_list(&self.inputs_and_output.internal(tables, tcx)),
             c_variadic: self.c_variadic,
-            unsafety: self.unsafety.internal(tables, tcx),
+            safety: self.safety.internal(tables, tcx),
             abi: self.abi.internal(tables, tcx),
         })
         .unwrap()
@@ -481,16 +481,15 @@ impl RustcInternal for Abi {
 }
 
 impl RustcInternal for Safety {
-    type T<'tcx> = rustc_hir::Unsafety;
+    type T<'tcx> = rustc_hir::Safety;
 
     fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
         match self {
-            Safety::Unsafe => rustc_hir::Unsafety::Unsafe,
-            Safety::Normal => rustc_hir::Unsafety::Normal,
+            Safety::Unsafe => rustc_hir::Safety::Unsafe,
+            Safety::Safe => rustc_hir::Safety::Safe,
         }
     }
 }
-
 impl RustcInternal for Span {
     type T<'tcx> = rustc_span::Span;
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
index 41b0a84dd80..736378a530f 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
@@ -9,12 +9,12 @@ mod error;
 mod mir;
 mod ty;
 
-impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety {
+impl<'tcx> Stable<'tcx> for rustc_hir::Safety {
     type T = stable_mir::mir::Safety;
     fn stable(&self, _: &mut Tables<'_>) -> Self::T {
         match self {
-            rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe,
-            rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal,
+            rustc_hir::Safety::Unsafe => stable_mir::mir::Safety::Unsafe,
+            rustc_hir::Safety::Safe => stable_mir::mir::Safety::Safe,
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 44737e6ce40..d59318be720 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -112,8 +112,8 @@ impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion {
         match self {
             PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer,
             PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer,
-            PointerCoercion::ClosureFnPointer(unsafety) => {
-                stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable(tables))
+            PointerCoercion::ClosureFnPointer(safety) => {
+                stable_mir::mir::PointerCoercion::ClosureFnPointer(safety.stable(tables))
             }
             PointerCoercion::MutToConstPointer => {
                 stable_mir::mir::PointerCoercion::MutToConstPointer
@@ -215,7 +215,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
         FnSig {
             inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(),
             c_variadic: self.c_variadic,
-            unsafety: self.unsafety.stable(tables),
+            safety: self.safety.stable(tables),
             abi: self.abi.stable(tables),
         }
     }
@@ -499,7 +499,7 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef {
 
         TraitDecl {
             def_id: tables.trait_def(self.def_id),
-            unsafety: self.unsafety.stable(tables),
+            safety: self.safety.stable(tables),
             paren_sugar: self.paren_sugar,
             has_auto_impl: self.has_auto_impl,
             is_marker: self.is_marker,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d41059e8c24..68b1b32baf2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -782,6 +782,8 @@ symbols! {
         explicit_tail_calls,
         export_name,
         expr,
+        expr_2021,
+        expr_fragment_specifier_2024,
         extended_key_value_attributes,
         extended_varargs_abi_support,
         extern_absolute_paths,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 9fb217d2f84..57b1542ff5a 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -424,7 +424,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             ty::FnPtr(sig) => {
                 self.push("F");
                 self.in_binder(&sig, |cx, sig| {
-                    if sig.unsafety == hir::Unsafety::Unsafe {
+                    if sig.safety == hir::Safety::Unsafe {
                         cx.push("U");
                     }
                     match sig.abi {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 8ba945e193c..910c6aeb7d6 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -612,6 +612,12 @@ impl LinkSelfContainedDefault {
             _ => "crt-objects-fallback",
         }
     }
+
+    /// Creates a `LinkSelfContainedDefault` enabling the self-contained linker for target specs
+    /// (the equivalent of `-Clink-self-contained=+linker` on the CLI).
+    pub fn with_linker() -> LinkSelfContainedDefault {
+        LinkSelfContainedDefault::WithComponents(LinkSelfContainedComponents::LINKER)
+    }
 }
 
 bitflags::bitflags! {
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
index 11fb28a9aed..bd12d4d8af0 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
@@ -18,6 +18,13 @@ pub fn target() -> Target {
         | SanitizerSet::THREAD;
     base.supports_xray = true;
 
+    // When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using
+    // linker flavor, and self-contained linker component.
+    if option_env!("CFG_USE_SELF_CONTAINED_LINKER").is_some() {
+        base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes);
+        base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker();
+    }
+
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index 811eb4c9810..1f4fb57d996 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+derivative = "2.2.0"
 itertools = "0.12"
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_ir = { path = "../rustc_ast_ir" }
@@ -21,10 +22,13 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
 rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_query_system = { path = "../rustc_query_system" }
+rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
+rustc_type_ir = { path = "../rustc_type_ir" }
+rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 3dc55509dad..fc852293dff 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -10,7 +10,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryRes
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, ToPredicate};
+use rustc_middle::ty::{GenericArg, Upcast};
 use rustc_span::DUMMY_SP;
 
 use std::fmt::Debug;
@@ -63,7 +63,7 @@ impl<'tcx> InferCtxt<'tcx> {
             cause: traits::ObligationCause::dummy(),
             param_env,
             recursion_depth: 0,
-            predicate: ty::Binder::dummy(trait_ref).to_predicate(self.tcx),
+            predicate: trait_ref.upcast(self.tcx),
         };
         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 97bea28f06a..b1dd6ae6611 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -13,7 +13,7 @@ use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{fast_reject, TypeFoldable};
-use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
+use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 use std::fmt::Debug;
 
@@ -25,7 +25,7 @@ pub(super) mod structural_traits;
 /// and the `result` when using the given `source`.
 #[derive(Debug, Clone)]
 pub(super) struct Candidate<'tcx> {
-    pub(super) source: CandidateSource,
+    pub(super) source: CandidateSource<'tcx>,
     pub(super) result: CanonicalResponse<'tcx>,
 }
 
@@ -47,7 +47,7 @@ pub(super) trait GoalKind<'tcx>:
     /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
     fn probe_and_match_goal_against_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
         then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
@@ -58,7 +58,7 @@ pub(super) trait GoalKind<'tcx>:
     /// goal by equating it with the assumption.
     fn probe_and_consider_implied_clause(
         ecx: &mut EvalCtxt<'_, 'tcx>,
-        parent_source: CandidateSource,
+        parent_source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
         requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
@@ -76,7 +76,7 @@ pub(super) trait GoalKind<'tcx>:
     /// since they're not implied by the well-formedness of the object type.
     fn probe_and_consider_object_bound_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -286,7 +286,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
         }
 
-        let goal =
+        let goal: Goal<'tcx, G> =
             goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty));
         // Vars that show up in the rest of the goal substs may have been constrained by
         // normalizing the self type as well, since type variables are not uniquified.
@@ -744,7 +744,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                     ecx,
                     CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }),
                     goal,
-                    assumption.to_predicate(tcx),
+                    assumption.upcast(tcx),
                 ));
             });
         }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 9e844d78702..cf826596392 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -7,9 +7,7 @@ use rustc_infer::traits::query::NoSolution;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
 use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::{
-    self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast};
 use rustc_span::sym;
 
 use crate::solve::EvalCtxt;
@@ -429,7 +427,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                         tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
                         [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
                     )
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 );
 
                 coroutine_closure_to_ambiguous_coroutine(
@@ -456,7 +454,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
             let nested = vec![
                 bound_sig
                     .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
             ];
             let future_output_def_id = tcx
                 .associated_items(future_trait_def_id)
@@ -484,7 +482,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
             let mut nested = vec![
                 bound_sig
                     .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
             ];
 
             // Additionally, we need to check that the closure kind
@@ -510,7 +508,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                         async_fn_kind_trait_def_id,
                         [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
                     )
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 );
             }
 
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 2058650f288..52deb22098f 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -40,13 +40,13 @@ trait ResponseT<'tcx> {
     fn var_values(&self) -> CanonicalVarValues<'tcx>;
 }
 
-impl<'tcx> ResponseT<'tcx> for Response<'tcx> {
+impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> {
     fn var_values(&self) -> CanonicalVarValues<'tcx> {
         self.var_values
     }
 }
 
-impl<'tcx, T> ResponseT<'tcx> for inspect::State<'tcx, T> {
+impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> {
     fn var_values(&self) -> CanonicalVarValues<'tcx> {
         self.var_values
     }
@@ -384,7 +384,7 @@ pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>
     var_values: &[ty::GenericArg<'tcx>],
     max_input_universe: ty::UniverseIndex,
     data: T,
-) -> inspect::CanonicalState<'tcx, T> {
+) -> inspect::CanonicalState<TyCtxt<'tcx>, T> {
     let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) };
     let state = inspect::State { var_values, data };
     let state = state.fold_with(&mut EagerResolver::new(infcx));
@@ -414,7 +414,7 @@ pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
     orig_values: &mut Vec<ty::GenericArg<'tcx>>,
-    state: inspect::CanonicalState<'tcx, T>,
+    state: inspect::CanonicalState<TyCtxt<'tcx>, T>,
 ) -> T {
     // In case any fresh inference variables have been created between `state`
     // and the previous instantiation, extend `orig_values` for it.
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index e5d26e530ee..70308d4359d 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -1,3 +1,6 @@
+use std::io::Write;
+use std::ops::ControlFlow;
+
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::at::ToTrace;
@@ -8,13 +11,12 @@ use rustc_infer::infer::{
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals};
 use rustc_infer::traits::ObligationCause;
-use rustc_macros::{extension, HashStable};
+use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_middle::bug;
 use rustc_middle::infer::canonical::CanonicalVarInfos;
-use rustc_middle::traits::solve::inspect;
 use rustc_middle::traits::solve::{
-    CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, PredefinedOpaquesData,
-    QueryResult,
+    inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques,
+    PredefinedOpaquesData, QueryResult,
 };
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::{
@@ -23,8 +25,8 @@ use rustc_middle::ty::{
 };
 use rustc_session::config::DumpSolverProofTree;
 use rustc_span::DUMMY_SP;
-use std::io::Write;
-use std::ops::ControlFlow;
+use rustc_type_ir::{self as ir, Interner};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::traits::coherence;
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
@@ -85,7 +87,7 @@ pub struct EvalCtxt<'a, 'tcx> {
 
     pub(super) search_graph: &'a mut SearchGraph<'tcx>,
 
-    nested_goals: NestedGoals<'tcx>,
+    nested_goals: NestedGoals<TyCtxt<'tcx>>,
 
     // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`?
     //
@@ -95,11 +97,15 @@ pub struct EvalCtxt<'a, 'tcx> {
     // evaluation code.
     tainted: Result<(), NoSolution>,
 
-    pub(super) inspect: ProofTreeBuilder<'tcx>,
+    pub(super) inspect: ProofTreeBuilder<TyCtxt<'tcx>>,
 }
 
-#[derive(Default, Debug, Clone)]
-pub(super) struct NestedGoals<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(Clone(bound = ""), Debug(bound = ""), Default(bound = ""))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TyDecodable, TyEncodable, HashStable_NoContext)]
+// FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate.
+pub struct NestedGoals<I: Interner> {
     /// These normalizes-to goals are treated specially during the evaluation
     /// loop. In each iteration we take the RHS of the projection, replace it with
     /// a fresh inference variable, and only after evaluating that goal do we
@@ -110,17 +116,17 @@ pub(super) struct NestedGoals<'tcx> {
     ///
     /// Forgetting to replace the RHS with a fresh inference variable when we evaluate
     /// this goal results in an ICE..
-    pub(super) normalizes_to_goals: Vec<Goal<'tcx, ty::NormalizesTo<'tcx>>>,
+    pub normalizes_to_goals: Vec<ir::solve::Goal<I, ir::NormalizesTo<I>>>,
     /// The rest of the goals which have not yet processed or remain ambiguous.
-    pub(super) goals: Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
+    pub goals: Vec<(GoalSource, ir::solve::Goal<I, I::Predicate>)>,
 }
 
-impl<'tcx> NestedGoals<'tcx> {
-    pub(super) fn new() -> Self {
+impl<I: Interner> NestedGoals<I> {
+    pub fn new() -> Self {
         Self { normalizes_to_goals: Vec::new(), goals: Vec::new() }
     }
 
-    pub(super) fn is_empty(&self) -> bool {
+    pub fn is_empty(&self) -> bool {
         self.normalizes_to_goals.is_empty() && self.goals.is_empty()
     }
 }
@@ -143,7 +149,8 @@ impl<'tcx> InferCtxt<'tcx> {
         &self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
         generate_proof_tree: GenerateProofTree,
-    ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<'tcx>>) {
+    ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>)
+    {
         EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
             ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
         })
@@ -166,7 +173,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         infcx: &InferCtxt<'tcx>,
         generate_proof_tree: GenerateProofTree,
         f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
-    ) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
+    ) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) {
         let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
         let mut search_graph = search_graph::SearchGraph::new(mode);
 
@@ -220,7 +227,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         search_graph: &'a mut search_graph::SearchGraph<'tcx>,
         canonical_input: CanonicalInput<'tcx>,
-        canonical_goal_evaluation: &mut ProofTreeBuilder<'tcx>,
+        canonical_goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
         f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
     ) -> R {
         let intercrate = match search_graph.solver_mode() {
@@ -282,7 +289,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         search_graph: &'a mut search_graph::SearchGraph<'tcx>,
         canonical_input: CanonicalInput<'tcx>,
-        goal_evaluation: &mut ProofTreeBuilder<'tcx>,
+        goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
     ) -> QueryResult<'tcx> {
         let mut canonical_goal_evaluation =
             goal_evaluation.new_canonical_goal_evaluation(canonical_input);
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index 47109c8ad5d..9edc489754c 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -2,10 +2,9 @@ use crate::solve::assembly::Candidate;
 
 use super::EvalCtxt;
 use rustc_infer::traits::BuiltinImplSource;
-use rustc_middle::traits::{
-    query::NoSolution,
-    solve::{inspect, CandidateSource, QueryResult},
-};
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
+use rustc_middle::ty::TyCtxt;
 use std::marker::PhantomData;
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
@@ -16,7 +15,7 @@ pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
 
 impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T>
 where
-    F: FnOnce(&T) -> inspect::ProbeKind<'tcx>,
+    F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>,
 {
     pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
         let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
@@ -51,12 +50,12 @@ where
 
 pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> {
     cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>,
-    source: CandidateSource,
+    source: CandidateSource<'tcx>,
 }
 
 impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F>
 where
-    F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
+    F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
 {
     #[instrument(level = "debug", skip_all, fields(source = ?self.source))]
     pub(in crate::solve) fn enter(
@@ -72,7 +71,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     /// as expensive as necessary to output the desired information.
     pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T>
     where
-        F: FnOnce(&T) -> inspect::ProbeKind<'tcx>,
+        F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>,
     {
         ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
     }
@@ -80,16 +79,24 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     pub(in crate::solve) fn probe_builtin_trait_candidate(
         &mut self,
         source: BuiltinImplSource,
-    ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
-    {
+    ) -> TraitProbeCtxt<
+        '_,
+        'a,
+        'tcx,
+        impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
+    > {
         self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
     }
 
     pub(in crate::solve) fn probe_trait_candidate(
         &mut self,
-        source: CandidateSource,
-    ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
-    {
+        source: CandidateSource<'tcx>,
+    ) -> TraitProbeCtxt<
+        '_,
+        'a,
+        'tcx,
+        impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
+    > {
         TraitProbeCtxt {
             cx: ProbeCtxt {
                 ecx: self,
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 3323f1bbf39..4933080451d 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -3,7 +3,6 @@ use std::ops::ControlFlow;
 
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
 use rustc_infer::traits::{
     self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
@@ -15,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::sym;
 
 use super::eval_ctxt::GenerateProofTree;
-use super::inspect::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
 use super::{Certainty, InferCtxtEvalExt};
 
 /// A trait engine using the new trait solver.
@@ -244,16 +243,23 @@ fn fulfillment_error_for_no_solution<'tcx>(
 
 fn fulfillment_error_for_stalled<'tcx>(
     infcx: &InferCtxt<'tcx>,
-    obligation: PredicateObligation<'tcx>,
+    root_obligation: PredicateObligation<'tcx>,
 ) -> FulfillmentError<'tcx> {
-    let code = infcx.probe(|_| {
-        match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 {
+    let (code, refine_obligation) = infcx.probe(|_| {
+        match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::Never).0 {
             Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
-                FulfillmentErrorCode::Ambiguity { overflow: None }
-            }
-            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => {
-                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }
+                (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
             }
+            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => (
+                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
+                // Don't look into overflows because we treat overflows weirdly anyways.
+                // In `instantiate_response_discarding_overflow` we set `has_changed = false`,
+                // recomputing the goal again during `find_best_leaf_obligation` may apply
+                // inference guidance that makes other goals go from ambig -> pass, for example.
+                //
+                // FIXME: We should probably just look into overflows here.
+                false,
+            ),
             Ok((_, Certainty::Yes)) => {
                 bug!("did not expect successful goal when collecting ambiguity errors")
             }
@@ -264,9 +270,13 @@ fn fulfillment_error_for_stalled<'tcx>(
     });
 
     FulfillmentError {
-        obligation: find_best_leaf_obligation(infcx, &obligation, true),
+        obligation: if refine_obligation {
+            find_best_leaf_obligation(infcx, &root_obligation, true)
+        } else {
+            root_obligation.clone()
+        },
         code,
-        root_obligation: obligation,
+        root_obligation,
     }
 }
 
@@ -302,41 +312,50 @@ impl<'tcx> BestObligation<'tcx> {
         res
     }
 
-    /// Filter out the candidates that aren't either error or ambiguous (depending
-    /// on what we are looking for), and also throw out candidates that have no
-    /// failing WC (or higher-ranked obligations, for which there should only be
-    /// one candidate anyways -- but I digress). This most likely means that the
-    /// goal just didn't unify at all, e.g. a param candidate with an alias in it.
+    /// Filter out the candidates that aren't interesting to visit for the
+    /// purposes of reporting errors. For ambiguities, we only consider
+    /// candidates that may hold. For errors, we only consider candidates that
+    /// *don't* hold and which have impl-where clauses that also don't hold.
     fn non_trivial_candidates<'a>(
         &self,
-        goal: &'a InspectGoal<'a, 'tcx>,
-    ) -> Vec<InspectCandidate<'a, 'tcx>> {
-        let mut candidates = goal
-            .candidates()
-            .into_iter()
-            .filter(|candidate| match self.consider_ambiguities {
-                true => matches!(candidate.result(), Ok(Certainty::Maybe(_))),
-                false => matches!(candidate.result(), Err(_)),
-            })
-            .collect::<Vec<_>>();
-
-        // If we have >1 candidate, one may still be due to "boring" reasons, like
-        // an alias-relate that failed to hold when deeply evaluated. We really
-        // don't care about reasons like this.
-        if candidates.len() > 1 {
-            candidates.retain(|candidate| {
-                goal.infcx().probe(|_| {
-                    candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| {
-                        matches!(
-                            nested_goal.source(),
-                            GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked
-                        ) && match self.consider_ambiguities {
-                            true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))),
-                            false => matches!(nested_goal.result(), Err(_)),
-                        }
-                    })
-                })
-            });
+        goal: &'a inspect::InspectGoal<'a, 'tcx>,
+    ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> {
+        let mut candidates = goal.candidates();
+        match self.consider_ambiguities {
+            true => {
+                // If we have an ambiguous obligation, we must consider *all* candidates
+                // that hold, or else we may guide inference causing other goals to go
+                // from ambig -> pass/fail.
+                candidates.retain(|candidate| candidate.result().is_ok());
+            }
+            false => {
+                // If we have >1 candidate, one may still be due to "boring" reasons, like
+                // an alias-relate that failed to hold when deeply evaluated. We really
+                // don't care about reasons like this.
+                if candidates.len() > 1 {
+                    candidates.retain(|candidate| {
+                        goal.infcx().probe(|_| {
+                            candidate.instantiate_nested_goals(self.span()).iter().any(
+                                |nested_goal| {
+                                    matches!(
+                                        nested_goal.source(),
+                                        GoalSource::ImplWhereBound
+                                            | GoalSource::InstantiateHigherRanked
+                                    ) && match self.consider_ambiguities {
+                                        true => {
+                                            matches!(
+                                                nested_goal.result(),
+                                                Ok(Certainty::Maybe(MaybeCause::Ambiguity))
+                                            )
+                                        }
+                                        false => matches!(nested_goal.result(), Err(_)),
+                                    }
+                                },
+                            )
+                        })
+                    });
+                }
+            }
         }
 
         candidates
@@ -350,58 +369,88 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
         self.obligation.cause.span
     }
 
-    fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
+    fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
         let candidates = self.non_trivial_candidates(goal);
         let [candidate] = candidates.as_slice() else {
             return ControlFlow::Break(self.obligation.clone());
         };
 
         // Don't walk into impls that have `do_not_recommend`.
-        if let ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } =
-            candidate.kind()
+        if let inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } = candidate.kind()
             && goal.infcx().tcx.has_attr(impl_def_id, sym::do_not_recommend)
         {
             return ControlFlow::Break(self.obligation.clone());
         }
 
-        // FIXME: Could we extract a trait ref from a projection here too?
+        let tcx = goal.infcx().tcx;
         // FIXME: Also, what about considering >1 layer up the stack? May be necessary
         // for normalizes-to.
-        let Some(parent_trait_pred) = goal.goal().predicate.to_opt_poly_trait_pred() else {
-            return ControlFlow::Break(self.obligation.clone());
+        let pred_kind = goal.goal().predicate.kind();
+        let child_mode = match pred_kind.skip_binder() {
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(parent_trait_pred)) => {
+                ChildMode::Trait(pred_kind.rebind(parent_trait_pred))
+            }
+            ty::PredicateKind::NormalizesTo(normalizes_to)
+                if matches!(
+                    normalizes_to.alias.kind(tcx),
+                    ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
+                ) =>
+            {
+                ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate {
+                    trait_ref: normalizes_to.alias.trait_ref(tcx),
+                    polarity: ty::PredicatePolarity::Positive,
+                }))
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
+                ChildMode::WellFormedObligation
+            }
+            _ => {
+                return ControlFlow::Break(self.obligation.clone());
+            }
         };
 
-        let tcx = goal.infcx().tcx;
         let mut impl_where_bound_count = 0;
         for nested_goal in candidate.instantiate_nested_goals(self.span()) {
+            let make_obligation = |cause| Obligation {
+                cause,
+                param_env: nested_goal.goal().param_env,
+                predicate: nested_goal.goal().predicate,
+                recursion_depth: self.obligation.recursion_depth + 1,
+            };
+
             let obligation;
-            match nested_goal.source() {
-                GoalSource::Misc => {
+            match (child_mode, nested_goal.source()) {
+                (ChildMode::Trait(_), GoalSource::Misc) => {
                     continue;
                 }
-                GoalSource::ImplWhereBound => {
-                    obligation = Obligation {
-                        cause: derive_cause(
-                            tcx,
-                            candidate.kind(),
-                            self.obligation.cause.clone(),
-                            impl_where_bound_count,
-                            parent_trait_pred,
-                        ),
-                        param_env: nested_goal.goal().param_env,
-                        predicate: nested_goal.goal().predicate,
-                        recursion_depth: self.obligation.recursion_depth + 1,
-                    };
+                (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
+                    obligation = make_obligation(derive_cause(
+                        tcx,
+                        candidate.kind(),
+                        self.obligation.cause.clone(),
+                        impl_where_bound_count,
+                        parent_trait_pred,
+                    ));
                     impl_where_bound_count += 1;
                 }
-                GoalSource::InstantiateHigherRanked => {
+                // Skip over a higher-ranked predicate.
+                (_, GoalSource::InstantiateHigherRanked) => {
                     obligation = self.obligation.clone();
                 }
+                (ChildMode::WellFormedObligation, _) => {
+                    obligation = make_obligation(self.obligation.cause.clone());
+                }
             }
 
             // Skip nested goals that aren't the *reason* for our goal's failure.
             match self.consider_ambiguities {
-                true if matches!(nested_goal.result(), Ok(Certainty::Maybe(_))) => {}
+                true if matches!(
+                    nested_goal.result(),
+                    Ok(Certainty::Maybe(MaybeCause::Ambiguity))
+                ) => {}
                 false if matches!(nested_goal.result(), Err(_)) => {}
                 _ => continue,
             }
@@ -413,15 +462,30 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
     }
 }
 
+#[derive(Copy, Clone)]
+enum ChildMode<'tcx> {
+    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
+    // and skip all `GoalSource::Misc`, which represent useless obligations
+    // such as alias-eq which may not hold.
+    Trait(ty::PolyTraitPredicate<'tcx>),
+    // Skip trying to derive an `ObligationCause` from this obligation, and
+    // report *all* sub-obligations as if they came directly from the parent
+    // obligation.
+    WellFormedObligation,
+}
+
 fn derive_cause<'tcx>(
     tcx: TyCtxt<'tcx>,
-    candidate_kind: ProbeKind<'tcx>,
+    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
     mut cause: ObligationCause<'tcx>,
     idx: usize,
     parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
 ) -> ObligationCause<'tcx> {
     match candidate_kind {
-        ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } => {
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } => {
             if let Some((_, span)) =
                 tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
             {
@@ -435,7 +499,10 @@ fn derive_cause<'tcx>(
                 })
             }
         }
-        ProbeKind::TraitCandidate { source: CandidateSource::BuiltinImpl(..), result: _ } => {
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::BuiltinImpl(..),
+            result: _,
+        } => {
             cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
         }
         _ => {}
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index b71a1b339cb..e12c66b6928 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -18,7 +18,7 @@ use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{inspect, QueryResult};
 use rustc_middle::traits::solve::{Certainty, Goal};
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::{TyCtxt, TypeFoldable};
 use rustc_middle::{bug, ty};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -37,7 +37,7 @@ pub struct InspectGoal<'a, 'tcx> {
     orig_values: Vec<ty::GenericArg<'tcx>>,
     goal: Goal<'tcx, ty::Predicate<'tcx>>,
     result: Result<Certainty, NoSolution>,
-    evaluation_kind: inspect::CanonicalGoalEvaluationKind<'tcx>,
+    evaluation_kind: inspect::CanonicalGoalEvaluationKind<TyCtxt<'tcx>>,
     normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
     source: GoalSource,
 }
@@ -88,16 +88,17 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
 
 pub struct InspectCandidate<'a, 'tcx> {
     goal: &'a InspectGoal<'a, 'tcx>,
-    kind: inspect::ProbeKind<'tcx>,
-    nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>,
-    final_state: inspect::CanonicalState<'tcx, ()>,
-    impl_args: Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>>,
+    kind: inspect::ProbeKind<TyCtxt<'tcx>>,
+    nested_goals:
+        Vec<(GoalSource, inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>)>,
+    final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>,
+    impl_args: Option<inspect::CanonicalState<TyCtxt<'tcx>, ty::GenericArgsRef<'tcx>>>,
     result: QueryResult<'tcx>,
     shallow_certainty: Certainty,
 }
 
 impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
-    pub fn kind(&self) -> inspect::ProbeKind<'tcx> {
+    pub fn kind(&self) -> inspect::ProbeKind<TyCtxt<'tcx>> {
         self.kind
     }
 
@@ -280,9 +281,9 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
         candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
         nested_goals: &mut Vec<(
             GoalSource,
-            inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>,
+            inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>,
         )>,
-        probe: &inspect::Probe<'tcx>,
+        probe: &inspect::Probe<TyCtxt<'tcx>>,
     ) {
         let mut shallow_certainty = None;
         let mut impl_args = None;
@@ -387,7 +388,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
     fn new(
         infcx: &'a InferCtxt<'tcx>,
         depth: usize,
-        root: inspect::GoalEvaluation<'tcx>,
+        root: inspect::GoalEvaluation<TyCtxt<'tcx>>,
         normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
         source: GoalSource,
     ) -> Self {
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 9dd681f09e7..803300c5196 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -9,11 +9,12 @@ use rustc_infer::infer::InferCtxt;
 use rustc_middle::bug;
 use rustc_middle::infer::canonical::CanonicalVarValues;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::{
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_next_trait_solver::solve::{
     CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
 };
-use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::DumpSolverProofTree;
+use rustc_type_ir::Interner;
 
 use crate::solve::eval_ctxt::canonical;
 use crate::solve::{self, inspect, GenerateProofTree};
@@ -38,49 +39,51 @@ use crate::solve::{self, inspect, GenerateProofTree};
 /// trees. At the end of trait solving `ProofTreeBuilder::finalize`
 /// is called to recursively convert the whole structure to a
 /// finished proof tree.
-pub(in crate::solve) struct ProofTreeBuilder<'tcx> {
-    state: Option<Box<DebugSolver<'tcx>>>,
+pub(in crate::solve) struct ProofTreeBuilder<I: Interner> {
+    state: Option<Box<DebugSolver<I>>>,
 }
 
 /// The current state of the proof tree builder, at most places
 /// in the code, only one or two variants are actually possible.
 ///
 /// We simply ICE in case that assumption is broken.
-#[derive(Debug)]
-enum DebugSolver<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""))]
+enum DebugSolver<I: Interner> {
     Root,
-    GoalEvaluation(WipGoalEvaluation<'tcx>),
-    CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>),
-    GoalEvaluationStep(WipGoalEvaluationStep<'tcx>),
+    GoalEvaluation(WipGoalEvaluation<I>),
+    CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<I>),
+    GoalEvaluationStep(WipGoalEvaluationStep<I>),
 }
 
-impl<'tcx> From<WipGoalEvaluation<'tcx>> for DebugSolver<'tcx> {
-    fn from(g: WipGoalEvaluation<'tcx>) -> DebugSolver<'tcx> {
+impl<I: Interner> From<WipGoalEvaluation<I>> for DebugSolver<I> {
+    fn from(g: WipGoalEvaluation<I>) -> DebugSolver<I> {
         DebugSolver::GoalEvaluation(g)
     }
 }
 
-impl<'tcx> From<WipCanonicalGoalEvaluation<'tcx>> for DebugSolver<'tcx> {
-    fn from(g: WipCanonicalGoalEvaluation<'tcx>) -> DebugSolver<'tcx> {
+impl<I: Interner> From<WipCanonicalGoalEvaluation<I>> for DebugSolver<I> {
+    fn from(g: WipCanonicalGoalEvaluation<I>) -> DebugSolver<I> {
         DebugSolver::CanonicalGoalEvaluation(g)
     }
 }
 
-impl<'tcx> From<WipGoalEvaluationStep<'tcx>> for DebugSolver<'tcx> {
-    fn from(g: WipGoalEvaluationStep<'tcx>) -> DebugSolver<'tcx> {
+impl<I: Interner> From<WipGoalEvaluationStep<I>> for DebugSolver<I> {
+    fn from(g: WipGoalEvaluationStep<I>) -> DebugSolver<I> {
         DebugSolver::GoalEvaluationStep(g)
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipGoalEvaluation<'tcx> {
-    pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    pub kind: WipGoalEvaluationKind<'tcx>,
-    pub evaluation: Option<WipCanonicalGoalEvaluation<'tcx>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipGoalEvaluation<I: Interner> {
+    pub uncanonicalized_goal: Goal<I, I::Predicate>,
+    pub kind: WipGoalEvaluationKind<I>,
+    pub evaluation: Option<WipCanonicalGoalEvaluation<I>>,
 }
 
-impl<'tcx> WipGoalEvaluation<'tcx> {
-    fn finalize(self) -> inspect::GoalEvaluation<'tcx> {
+impl<I: Interner> WipGoalEvaluation<I> {
+    fn finalize(self) -> inspect::GoalEvaluation<I> {
         inspect::GoalEvaluation {
             uncanonicalized_goal: self.uncanonicalized_goal,
             kind: match self.kind {
@@ -94,21 +97,23 @@ impl<'tcx> WipGoalEvaluation<'tcx> {
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-pub(in crate::solve) enum WipGoalEvaluationKind<'tcx> {
-    Root { orig_values: Vec<ty::GenericArg<'tcx>> },
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+pub(in crate::solve) enum WipGoalEvaluationKind<I: Interner> {
+    Root { orig_values: Vec<I::GenericArg> },
     Nested,
 }
 
-#[derive(Eq, PartialEq)]
-pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""))]
+pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<I: Interner> {
     Overflow,
     CycleInStack,
     ProvisionalCacheHit,
-    Interned { revisions: &'tcx [inspect::GoalEvaluationStep<'tcx>] },
+    Interned { revisions: I::GoalEvaluationSteps },
 }
 
-impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> {
+impl<I: Interner> std::fmt::Debug for WipCanonicalGoalEvaluationKind<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             Self::Overflow => write!(f, "Overflow"),
@@ -119,18 +124,19 @@ impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> {
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipCanonicalGoalEvaluation<'tcx> {
-    goal: CanonicalInput<'tcx>,
-    kind: Option<WipCanonicalGoalEvaluationKind<'tcx>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipCanonicalGoalEvaluation<I: Interner> {
+    goal: CanonicalInput<I>,
+    kind: Option<WipCanonicalGoalEvaluationKind<I>>,
     /// Only used for uncached goals. After we finished evaluating
     /// the goal, this is interned and moved into `kind`.
-    revisions: Vec<WipGoalEvaluationStep<'tcx>>,
-    result: Option<QueryResult<'tcx>>,
+    revisions: Vec<WipGoalEvaluationStep<I>>,
+    result: Option<QueryResult<I>>,
 }
 
-impl<'tcx> WipCanonicalGoalEvaluation<'tcx> {
-    fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> {
+impl<I: Interner> WipCanonicalGoalEvaluation<I> {
+    fn finalize(self) -> inspect::CanonicalGoalEvaluation<I> {
         assert!(self.revisions.is_empty());
         let kind = match self.kind.unwrap() {
             WipCanonicalGoalEvaluationKind::Overflow => {
@@ -151,14 +157,15 @@ impl<'tcx> WipCanonicalGoalEvaluation<'tcx> {
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipAddedGoalsEvaluation<'tcx> {
-    evaluations: Vec<Vec<WipGoalEvaluation<'tcx>>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipAddedGoalsEvaluation<I: Interner> {
+    evaluations: Vec<Vec<WipGoalEvaluation<I>>>,
     result: Option<Result<Certainty, NoSolution>>,
 }
 
-impl<'tcx> WipAddedGoalsEvaluation<'tcx> {
-    fn finalize(self) -> inspect::AddedGoalsEvaluation<'tcx> {
+impl<I: Interner> WipAddedGoalsEvaluation<I> {
+    fn finalize(self) -> inspect::AddedGoalsEvaluation<I> {
         inspect::AddedGoalsEvaluation {
             evaluations: self
                 .evaluations
@@ -172,22 +179,23 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> {
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipGoalEvaluationStep<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipGoalEvaluationStep<I: Interner> {
     /// Unlike `EvalCtxt::var_values`, we append a new
     /// generic arg here whenever we create a new inference
     /// variable.
     ///
     /// This is necessary as we otherwise don't unify these
     /// vars when instantiating multiple `CanonicalState`.
-    var_values: Vec<ty::GenericArg<'tcx>>,
-    instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
+    var_values: Vec<I::GenericArg>,
+    instantiated_goal: QueryInput<I, I::Predicate>,
     probe_depth: usize,
-    evaluation: WipProbe<'tcx>,
+    evaluation: WipProbe<I>,
 }
 
-impl<'tcx> WipGoalEvaluationStep<'tcx> {
-    fn current_evaluation_scope(&mut self) -> &mut WipProbe<'tcx> {
+impl<I: Interner> WipGoalEvaluationStep<I> {
+    fn current_evaluation_scope(&mut self) -> &mut WipProbe<I> {
         let mut current = &mut self.evaluation;
         for _ in 0..self.probe_depth {
             match current.steps.last_mut() {
@@ -198,7 +206,7 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> {
         current
     }
 
-    fn added_goals_evaluation(&mut self) -> &mut WipAddedGoalsEvaluation<'tcx> {
+    fn added_goals_evaluation(&mut self) -> &mut WipAddedGoalsEvaluation<I> {
         let mut current = &mut self.evaluation;
         loop {
             match current.steps.last_mut() {
@@ -209,7 +217,7 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> {
         }
     }
 
-    fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> {
+    fn finalize(self) -> inspect::GoalEvaluationStep<I> {
         let evaluation = self.evaluation.finalize();
         match evaluation.kind {
             inspect::ProbeKind::Root { .. } => (),
@@ -219,16 +227,17 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> {
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipProbe<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipProbe<I: Interner> {
     initial_num_var_values: usize,
-    steps: Vec<WipProbeStep<'tcx>>,
-    kind: Option<inspect::ProbeKind<'tcx>>,
-    final_state: Option<inspect::CanonicalState<'tcx, ()>>,
+    steps: Vec<WipProbeStep<I>>,
+    kind: Option<inspect::ProbeKind<I>>,
+    final_state: Option<inspect::CanonicalState<I, ()>>,
 }
 
-impl<'tcx> WipProbe<'tcx> {
-    fn finalize(self) -> inspect::Probe<'tcx> {
+impl<I: Interner> WipProbe<I> {
+    fn finalize(self) -> inspect::Probe<I> {
         inspect::Probe {
             steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(),
             kind: self.kind.unwrap(),
@@ -237,17 +246,18 @@ impl<'tcx> WipProbe<'tcx> {
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-enum WipProbeStep<'tcx> {
-    AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
-    EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
-    NestedProbe(WipProbe<'tcx>),
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+enum WipProbeStep<I: Interner> {
+    AddGoal(GoalSource, inspect::CanonicalState<I, Goal<I, I::Predicate>>),
+    EvaluateGoals(WipAddedGoalsEvaluation<I>),
+    NestedProbe(WipProbe<I>),
     MakeCanonicalResponse { shallow_certainty: Certainty },
-    RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
+    RecordImplArgs { impl_args: inspect::CanonicalState<I, I::GenericArgs> },
 }
 
-impl<'tcx> WipProbeStep<'tcx> {
-    fn finalize(self) -> inspect::ProbeStep<'tcx> {
+impl<I: Interner> WipProbeStep<I> {
+    fn finalize(self) -> inspect::ProbeStep<I> {
         match self {
             WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
             WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
@@ -262,26 +272,27 @@ impl<'tcx> WipProbeStep<'tcx> {
     }
 }
 
-impl<'tcx> ProofTreeBuilder<'tcx> {
-    fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> {
+// FIXME: Genericize this impl.
+impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
+    fn new(state: impl Into<DebugSolver<TyCtxt<'tcx>>>) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         ProofTreeBuilder { state: Some(Box::new(state.into())) }
     }
 
-    fn nested<T: Into<DebugSolver<'tcx>>>(&self, state: impl FnOnce() -> T) -> Self {
+    fn nested<T: Into<DebugSolver<TyCtxt<'tcx>>>>(&self, state: impl FnOnce() -> T) -> Self {
         ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) }
     }
 
-    fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> {
+    fn as_mut(&mut self) -> Option<&mut DebugSolver<TyCtxt<'tcx>>> {
         self.state.as_deref_mut()
     }
 
-    pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<'tcx> {
+    pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         let mut nested = ProofTreeBuilder { state: self.state.take() };
         nested.enter_probe();
         nested
     }
 
-    pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> {
+    pub fn finalize(self) -> Option<inspect::GoalEvaluation<TyCtxt<'tcx>>> {
         match *self.state? {
             DebugSolver::GoalEvaluation(wip_goal_evaluation) => {
                 Some(wip_goal_evaluation.finalize())
@@ -293,7 +304,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     pub fn new_maybe_root(
         tcx: TyCtxt<'tcx>,
         generate_proof_tree: GenerateProofTree,
-    ) -> ProofTreeBuilder<'tcx> {
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         match generate_proof_tree {
             GenerateProofTree::Never => ProofTreeBuilder::new_noop(),
             GenerateProofTree::IfEnabled => {
@@ -311,11 +322,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn new_root() -> ProofTreeBuilder<'tcx> {
+    pub fn new_root() -> ProofTreeBuilder<TyCtxt<'tcx>> {
         ProofTreeBuilder::new(DebugSolver::Root)
     }
 
-    pub fn new_noop() -> ProofTreeBuilder<'tcx> {
+    pub fn new_noop() -> ProofTreeBuilder<TyCtxt<'tcx>> {
         ProofTreeBuilder { state: None }
     }
 
@@ -325,10 +336,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
 
     pub(in crate::solve) fn new_goal_evaluation(
         &mut self,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+        goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
         orig_values: &[ty::GenericArg<'tcx>],
         kind: solve::GoalEvaluationKind,
-    ) -> ProofTreeBuilder<'tcx> {
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         self.nested(|| WipGoalEvaluation {
             uncanonicalized_goal: goal,
             kind: match kind {
@@ -343,8 +354,8 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
 
     pub fn new_canonical_goal_evaluation(
         &mut self,
-        goal: CanonicalInput<'tcx>,
-    ) -> ProofTreeBuilder<'tcx> {
+        goal: CanonicalInput<TyCtxt<'tcx>>,
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         self.nested(|| WipCanonicalGoalEvaluation {
             goal,
             kind: None,
@@ -356,7 +367,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     pub fn finalize_evaluation(
         &mut self,
         tcx: TyCtxt<'tcx>,
-    ) -> Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]> {
+    ) -> Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]> {
         self.as_mut().map(|this| match this {
             DebugSolver::CanonicalGoalEvaluation(evaluation) => {
                 let revisions = mem::take(&mut evaluation.revisions)
@@ -371,7 +382,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         })
     }
 
-    pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<'tcx>) {
+    pub fn canonical_goal_evaluation(
+        &mut self,
+        canonical_goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>,
+    ) {
         if let Some(this) = self.as_mut() {
             match (this, *canonical_goal_evaluation.state.unwrap()) {
                 (
@@ -386,7 +400,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<'tcx>) {
+    pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
@@ -397,7 +411,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) {
+    pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match (this, *goal_evaluation.state.unwrap()) {
                 (
@@ -418,8 +432,8 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     pub fn new_goal_evaluation_step(
         &mut self,
         var_values: CanonicalVarValues<'tcx>,
-        instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
-    ) -> ProofTreeBuilder<'tcx> {
+        instantiated_goal: QueryInput<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         self.nested(|| WipGoalEvaluationStep {
             var_values: var_values.var_values.to_vec(),
             instantiated_goal,
@@ -433,7 +447,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         })
     }
 
-    pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) {
+    pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match (this, *goal_evaluation_step.state.unwrap()) {
                 (
@@ -474,7 +488,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<'tcx>) {
+    pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<TyCtxt<'tcx>>) {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::GoalEvaluationStep(state)) => {
@@ -510,7 +524,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         &mut self,
         infcx: &InferCtxt<'tcx>,
         max_input_universe: ty::UniverseIndex,
-        goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
+        goal: Goal<TyCtxt<'tcx>, ty::NormalizesTo<'tcx>>,
     ) {
         self.add_goal(
             infcx,
@@ -525,7 +539,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         infcx: &InferCtxt<'tcx>,
         max_input_universe: ty::UniverseIndex,
         source: GoalSource,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+        goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
     ) {
         match self.as_mut() {
             None => {}
@@ -579,7 +593,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn finish_probe(mut self) -> ProofTreeBuilder<'tcx> {
+    pub fn finish_probe(mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::GoalEvaluationStep(state)) => {
@@ -627,7 +641,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn query_result(&mut self, result: QueryResult<'tcx>) {
+    pub fn query_result(&mut self, result: QueryResult<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 6c912db975a..b085d009d75 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -22,9 +22,9 @@ use rustc_middle::infer::canonical::CanonicalVarInfos;
 use rustc_middle::traits::solve::{
     CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response,
 };
-use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{
-    CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
+    self, AliasRelationDirection, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, Ty,
+    TyCtxt, TypeOutlivesPredicate, UniverseIndex,
 };
 
 mod alias_relate;
@@ -74,7 +74,7 @@ enum GoalEvaluationKind {
 }
 
 #[extension(trait CanonicalResponseExt)]
-impl<'tcx> Canonical<'tcx, Response<'tcx>> {
+impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> {
     fn has_no_inference_or_external_constraints(&self) -> bool {
         self.value.external_constraints.region_constraints.is_empty()
             && self.value.var_values.is_identity()
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 6ec0ad9d29a..8c492b62c1a 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -3,7 +3,6 @@ use crate::traits::specialization_graph;
 use super::assembly::structural_traits::AsyncCallableRelevantTypes;
 use super::assembly::{self, structural_traits, Candidate};
 use super::{EvalCtxt, GoalSource};
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_infer::traits::query::NoSolution;
@@ -16,7 +15,7 @@ use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::NormalizesTo;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
+use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
 
@@ -54,23 +53,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         &mut self,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let def_id = goal.predicate.def_id();
-        match self.tcx().def_kind(def_id) {
-            DefKind::AssocTy | DefKind::AssocConst => {
-                match self.tcx().associated_item(def_id).container {
-                    ty::AssocItemContainer::TraitContainer => {
-                        let candidates = self.assemble_and_evaluate_candidates(goal);
-                        self.merge_candidates(candidates)
-                    }
-                    ty::AssocItemContainer::ImplContainer => {
-                        self.normalize_inherent_associated_type(goal)
-                    }
-                }
+        match goal.predicate.alias.kind(self.tcx()) {
+            ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
+                let candidates = self.assemble_and_evaluate_candidates(goal);
+                self.merge_candidates(candidates)
             }
-            DefKind::AnonConst => self.normalize_anon_const(goal),
-            DefKind::TyAlias => self.normalize_weak_type(goal),
-            DefKind::OpaqueTy => self.normalize_opaque_type(goal),
-            kind => bug!("unknown DefKind {} in normalizes-to goal: {goal:#?}", kind.descr(def_id)),
+            ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal),
+            ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal),
+            ty::AliasTermKind::WeakTy => self.normalize_weak_type(goal),
+            ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal),
         }
     }
 
@@ -108,7 +99,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
 
     fn probe_and_match_goal_against_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
         then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
@@ -370,7 +361,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 ),
                 term: output.into(),
             })
-            .to_predicate(tcx);
+            .upcast(tcx);
 
         // A built-in `Fn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
@@ -452,7 +443,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                     ty::ProjectionPredicate { projection_term, term }
                 },
             )
-            .to_predicate(tcx);
+            .upcast(tcx);
 
         // A built-in `AsyncFn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
@@ -629,7 +620,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
                 term,
             }
-            .to_predicate(tcx),
+            .upcast(tcx),
             // Technically, we need to check that the future type is Sized,
             // but that's already proven by the coroutine being WF.
             [],
@@ -661,7 +652,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
                 term,
             }
-            .to_predicate(tcx),
+            .upcast(tcx),
             // Technically, we need to check that the iterator type is Sized,
             // but that's already proven by the generator being WF.
             [],
@@ -749,7 +740,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 ),
                 term,
             }
-            .to_predicate(tcx),
+            .upcast(tcx),
             // Technically, we need to check that the coroutine type is Sized,
             // but that's already proven by the coroutine being WF.
             [],
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index 60362aa01da..0164d44667c 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
@@ -253,8 +253,8 @@ impl<'tcx> SearchGraph<'tcx> {
         &mut self,
         tcx: TyCtxt<'tcx>,
         input: CanonicalInput<'tcx>,
-        inspect: &mut ProofTreeBuilder<'tcx>,
-        mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>,
+        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> QueryResult<'tcx> {
         // Check for overflow.
         let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else {
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 1cafa970b68..9139c75d399 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -15,7 +15,7 @@ use rustc_middle::traits::solve::inspect::ProbeKind;
 use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
 use rustc_middle::traits::{BuiltinImplSource, Reveal};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
 use rustc_span::ErrorGuaranteed;
 
@@ -103,7 +103,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
     fn probe_and_match_goal_against_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
         then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
@@ -315,7 +315,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             .map_bound(|(inputs, _)| {
                 ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
             })
-            .to_predicate(tcx);
+            .upcast(tcx);
         // A built-in `Fn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
@@ -363,7 +363,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     [goal.predicate.self_ty(), tupled_inputs_ty],
                 )
             })
-            .to_predicate(tcx);
+            .upcast(tcx);
         // A built-in `AsyncFn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
@@ -560,7 +560,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
             goal,
             ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
-                .to_predicate(tcx),
+                .upcast(tcx),
             // Technically, we need to check that the coroutine types are Sized,
             // but that's already proven by the coroutine being WF.
             [],
@@ -821,7 +821,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     fn consider_builtin_upcast_to_principal(
         &mut self,
         goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
         a_region: ty::Region<'tcx>,
         b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@@ -1149,7 +1149,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     /// wrapped in one.
     fn probe_and_evaluate_goal_for_constituent_tys(
         &mut self,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         constituent_tys: impl Fn(
             &EvalCtxt<'_, 'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 60562acfe93..1ea207cc375 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -303,7 +303,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 Err(SelectionError::Unimplemented) => {
                     if self.is_param_no_infer(pred.skip_binder().trait_ref.args) {
                         already_visited.remove(&pred);
-                        self.add_user_pred(&mut user_computed_preds, pred.to_predicate(self.tcx));
+                        self.add_user_pred(&mut user_computed_preds, pred.upcast(self.tcx));
                         predicates.push_back(pred);
                     } else {
                         debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 551c8e7702e..4684c7171d8 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -25,8 +25,8 @@ use rustc_macros::extension;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::Variance;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -96,7 +96,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
             cause,
             recursion_depth: 0,
             param_env,
-            predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
+            predicate: trait_ref.upcast(tcx),
         });
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 7fc94b31b3b..32c8a454b40 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -205,9 +205,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
             if self_ty.is_fn() {
                 let fn_sig = self_ty.fn_sig(self.tcx);
-                let shortname = match fn_sig.unsafety() {
-                    hir::Unsafety::Normal => "fn",
-                    hir::Unsafety::Unsafe => "unsafe fn",
+                let shortname = match fn_sig.safety() {
+                    hir::Safety::Safe => "fn",
+                    hir::Safety::Unsafe => "unsafe fn",
                 };
                 flags.push((sym::_Self, Some(shortname.to_owned())));
             }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 86610855441..f9b6b281f92 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -31,8 +31,8 @@ use rustc_middle::traits::IsConstable;
 use rustc_middle::ty::error::TypeError::{self, Sorts};
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
-    InferTy, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt, TypeckResults,
+    InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, TypeckResults, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::LocalDefId;
@@ -192,7 +192,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
-            predicate_constraint(hir_generics, trait_pred.to_predicate(tcx)),
+            predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
         ];
         sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
 
@@ -215,7 +215,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
                 .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
             super_traits,
         ) {
-            (_, None) => predicate_constraint(hir_generics, trait_pred.to_predicate(tcx)),
+            (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
             (None, Some((ident, []))) => (
                 ident.span.shrink_to_hi(),
                 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
@@ -1897,7 +1897,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         *inputs,
                         infcx.next_ty_var(DUMMY_SP),
                         false,
-                        hir::Unsafety::Normal,
+                        hir::Safety::Safe,
                         abi::Abi::Rust,
                     )
                 }
@@ -1905,7 +1905,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     [inputs],
                     infcx.next_ty_var(DUMMY_SP),
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     abi::Abi::Rust,
                 ),
             };
@@ -2703,12 +2703,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
     ) where
-        T: ToPredicate<'tcx>,
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
     {
         let mut long_ty_file = None;
 
         let tcx = self.tcx;
-        let predicate = predicate.to_predicate(tcx);
+        let predicate = predicate.upcast(tcx);
         match *cause_code {
             ObligationCauseCode::ExprAssignable
             | ObligationCauseCode::MatchExpressionArm { .. }
@@ -2739,7 +2739,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             | ObligationCauseCode::ReferenceOutlivesReferent(..)
             | ObligationCauseCode::ObjectTypeBound(..) => {}
             ObligationCauseCode::RustCall => {
-                if let Some(pred) = predicate.to_opt_poly_trait_pred()
+                if let Some(pred) = predicate.as_trait_clause()
                     && Some(pred.def_id()) == tcx.lang_items().sized_trait()
                 {
                     err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
@@ -3378,7 +3378,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             break;
                         }
                         data = derived;
-                        parent_predicate = child_trait_ref.to_predicate(tcx);
+                        parent_predicate = child_trait_ref.upcast(tcx);
                         parent_trait_pred = child_trait_ref;
                     }
                 }
@@ -3392,7 +3392,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     }
                     count += 1;
                     data = &child.derived;
-                    parent_predicate = child_trait_pred.to_predicate(tcx);
+                    parent_predicate = child_trait_pred.upcast(tcx);
                     parent_trait_pred = child_trait_pred;
                 }
                 if count > 0 {
@@ -3725,7 +3725,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         {
             if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr
                 && let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id)
-                && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
+                && let Some(failed_pred) = failed_pred.as_trait_clause()
                 && let pred = failed_pred.map_bound(|pred| pred.with_self_ty(tcx, ty))
                 && self.predicate_must_hold_modulo_regions(&Obligation::misc(
                     tcx, expr.span, body_id, param_env, pred,
@@ -3816,7 +3816,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 && let Some(where_pred) = where_clauses.predicates.get(*idx)
             {
                 if let Some(where_pred) = where_pred.as_trait_clause()
-                    && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
+                    && let Some(failed_pred) = failed_pred.as_trait_clause()
                 {
                     self.enter_forall(where_pred, |where_pred| {
                         let failed_pred = self.instantiate_binder_with_fresh_vars(
@@ -3842,7 +3842,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         }
                     })
                 } else if let Some(where_pred) = where_pred.as_projection_clause()
-                    && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
+                    && let Some(failed_pred) = failed_pred.as_projection_clause()
                     && let Some(found) = failed_pred.skip_binder().term.ty()
                 {
                     type_diffs = vec![Sorts(ty::error::ExpectedFound {
@@ -3925,7 +3925,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             && let fn_sig @ ty::FnSig {
                 abi: abi::Abi::Rust,
                 c_variadic: false,
-                unsafety: hir::Unsafety::Normal,
+                safety: hir::Safety::Safe,
                 ..
             } = fn_ty.fn_sig(tcx).skip_binder()
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index f9824acdae0..d693bac90dc 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -42,8 +42,8 @@ use rustc_middle::ty::print::{
     PrintTraitRefExt as _,
 };
 use rustc_middle::ty::{
-    self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
-    TypeVisitable, TypeVisitableExt,
+    self, SubtypePredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable,
+    TypeVisitableExt, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::DumpSolverProofTree;
@@ -302,9 +302,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         suggest_increasing_limit: bool,
     ) -> !
     where
-        T: ToPredicate<'tcx> + Clone,
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
     {
-        let predicate = obligation.predicate.clone().to_predicate(self.tcx);
+        let predicate = obligation.predicate.clone().upcast(self.tcx);
         let predicate = self.resolve_vars_if_possible(predicate);
         self.report_overflow_error(
             OverflowCause::TraitSolver(predicate),
@@ -1417,7 +1417,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         };
 
         let mut code = obligation.cause.code();
-        let mut pred = obligation.predicate.to_opt_poly_trait_pred();
+        let mut pred = obligation.predicate.as_trait_clause();
         while let Some((next_code, next_pred)) = code.parent() {
             if let Some(pred) = pred {
                 self.enter_forall(pred, |pred| {
@@ -1481,16 +1481,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             return true;
         }
 
-        if let Some(error) = error.to_opt_poly_trait_pred() {
+        if let Some(error) = error.as_trait_clause() {
             self.enter_forall(error, |error| {
                 elaborate(self.tcx, std::iter::once(cond))
-                    .filter_map(|implied| implied.to_opt_poly_trait_pred())
+                    .filter_map(|implied| implied.as_trait_clause())
                     .any(|implied| self.can_match_trait(error, implied))
             })
-        } else if let Some(error) = error.to_opt_poly_projection_pred() {
+        } else if let Some(error) = error.as_projection_clause() {
             self.enter_forall(error, |error| {
                 elaborate(self.tcx, std::iter::once(cond))
-                    .filter_map(|implied| implied.to_opt_poly_projection_pred())
+                    .filter_map(|implied| implied.as_projection_clause())
                     .any(|implied| self.can_match_projection(error, implied))
             })
         } else {
@@ -2415,8 +2415,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         return e;
                     }
                     err.note(format!("cannot satisfy `{predicate}`"));
-                    let impl_candidates = self
-                        .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap());
+                    let impl_candidates =
+                        self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
                     if impl_candidates.len() < 40 {
                         self.report_similar_impl_candidates(
                             impl_candidates.as_slice(),
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 61f47bc1f23..204bb487c86 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -34,7 +34,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFolder, TypeSuperVisitable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
@@ -142,7 +142,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
 fn pred_known_to_hold_modulo_regions<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    pred: impl ToPredicate<'tcx>,
+    pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
 ) -> bool {
     let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
 
@@ -457,7 +457,7 @@ fn instantiate_and_check_impossible_predicates<'tcx>(
     // associated items.
     if let Some(trait_def_id) = tcx.trait_of_item(key.0) {
         let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1);
-        predicates.push(ty::Binder::dummy(trait_ref).to_predicate(tcx));
+        predicates.push(trait_ref.upcast(tcx));
     }
 
     predicates.retain(|predicate| !predicate.has_param());
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 41080b3d9d3..abb19c7efd8 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::{
     TypeVisitable, TypeVisitor,
 };
 use rustc_middle::ty::{GenericArg, GenericArgs};
-use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
+use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -649,11 +649,11 @@ fn object_ty_for_trait<'tcx>(
     ));
     debug!(?trait_predicate);
 
-    let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
+    let pred: ty::Predicate<'tcx> = trait_ref.upcast(tcx);
     let mut elaborated_predicates: Vec<_> = elaborate(tcx, [pred])
         .filter_map(|pred| {
             debug!(?pred);
-            let pred = pred.to_opt_poly_projection_pred()?;
+            let pred = pred.as_projection_clause()?;
             Some(pred.map_bound(|p| {
                 ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
                     tcx, p,
@@ -752,8 +752,7 @@ fn receiver_is_dispatchable<'tcx>(
 
         // Self: Unsize<U>
         let unsize_predicate =
-            ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty])
-                .to_predicate(tcx);
+            ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]).upcast(tcx);
 
         // U: Trait<Arg1, ..., ArgN>
         let trait_predicate = {
@@ -762,7 +761,7 @@ fn receiver_is_dispatchable<'tcx>(
                 if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
             });
 
-            ty::TraitRef::new(tcx, trait_def_id, args).to_predicate(tcx)
+            ty::TraitRef::new(tcx, trait_def_id, args).upcast(tcx)
         };
 
         let caller_bounds =
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 2e7d2790dc3..77ac4be35ea 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -35,7 +35,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast};
 use rustc_span::symbol::sym;
 
 pub use rustc_middle::traits::Reveal;
@@ -538,7 +538,7 @@ fn normalize_to_error<'a, 'tcx>(
         cause,
         recursion_depth: depth,
         param_env,
-        predicate: trait_ref.to_predicate(selcx.tcx()),
+        predicate: trait_ref.upcast(selcx.tcx()),
     };
     Normalized { value: new_value, obligations: vec![trait_obligation] }
 }
@@ -877,7 +877,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     let env_predicates = data
         .projection_bounds()
         .filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
-        .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
+        .map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx));
 
     assemble_candidates_from_predicates(
         selcx,
@@ -1712,7 +1712,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
                     [sig.tupled_inputs_ty],
                     output_ty,
                     sig.c_variadic,
-                    sig.unsafety,
+                    sig.safety,
                     sig.abi,
                 )
             })
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 24c6951a014..65048ffdfba 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -14,8 +14,8 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
-    TraitPredicate, Ty, TyCtxt,
+    self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TraitPredicate, Ty,
+    TyCtxt, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
@@ -676,7 +676,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let assoc_ty_args = tcx.mk_args(&args);
                     let bound =
                         bound.map_bound(|b| b.kind().skip_binder()).instantiate(tcx, assoc_ty_args);
-                    ty::Binder::bind_with_vars(bound, bound_vars).to_predicate(tcx)
+                    ty::Binder::bind_with_vars(bound, bound_vars).upcast(tcx)
                 };
                 let normalized_bound = normalize_with_depth_to(
                     self,
@@ -1253,13 +1253,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)),
                     [source],
                 );
-                nested.push(predicate_to_obligation(tr.to_predicate(tcx)));
+                nested.push(predicate_to_obligation(tr.upcast(tcx)));
 
                 // If the type is `Foo + 'a`, ensure that the type
                 // being cast to `Foo + 'a` outlives `'a`:
                 let outlives = ty::OutlivesPredicate(source, r);
                 nested.push(predicate_to_obligation(
-                    ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx),
+                    ty::ClauseKind::TypeOutlives(outlives).upcast(tcx),
                 ));
 
                 ImplSource::Builtin(BuiltinImplSource::Misc, nested)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5b25c62689f..19affac7970 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -45,7 +45,7 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, PolyProjectionPredicate, ToPredicate};
+use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
@@ -739,8 +739,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             // stack would be `T: Auto`.
                             let cycle = stack.iter().take_while(|s| s.depth > stack_arg.1);
                             let tcx = self.tcx();
-                            let cycle =
-                                cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx));
+                            let cycle = cycle.map(|stack| stack.obligation.predicate.upcast(tcx));
                             if self.coinductive_match(cycle) {
                                 stack.update_reached_depth(stack_arg.1);
                                 return Ok(EvaluatedToOk);
@@ -1174,7 +1173,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // if the regions match exactly.
             let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
             let tcx = self.tcx();
-            let cycle = cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx));
+            let cycle = cycle.map(|stack| stack.obligation.predicate.upcast(tcx));
             if self.coinductive_match(cycle) {
                 debug!("evaluate_stack --> recursive, coinductive");
                 Some(EvaluatedToOk)
@@ -1379,7 +1378,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         error_obligation: &Obligation<'tcx, T>,
     ) -> Result<(), OverflowError>
     where
-        T: ToPredicate<'tcx> + Clone,
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
     {
         if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
             match self.query_mode {
@@ -1408,7 +1407,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         error_obligation: &Obligation<'tcx, V>,
     ) -> Result<(), OverflowError>
     where
-        V: ToPredicate<'tcx> + Clone,
+        V: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
     {
         self.check_recursion_depth(obligation.recursion_depth, error_obligation)
     }
@@ -1779,9 +1778,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // If this type is a GAT, and of the GAT args resolve to something new,
             // that means that we must have newly inferred something about the GAT.
             // We should give up in that case.
+            // FIXME(generic-associated-types): This only detects one layer of inference,
+            // which is probably not what we actually want, but fixing it causes some ambiguity:
+            // <https://github.com/rust-lang/rust/issues/125196>.
             if !generics.own_params.is_empty()
                 && obligation.predicate.args[generics.parent_count..].iter().any(|&p| {
-                    p.has_non_region_infer() && self.infcx.resolve_vars_if_possible(p) != p
+                    p.has_non_region_infer()
+                        && match p.unpack() {
+                            ty::GenericArgKind::Const(ct) => {
+                                self.infcx.shallow_resolve_const(ct) != ct
+                            }
+                            ty::GenericArgKind::Type(ty) => self.infcx.shallow_resolve(ty) != ty,
+                            ty::GenericArgKind::Lifetime(_) => false,
+                        }
                 })
             {
                 ProjectionMatchesProjection::Ambiguous
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 83edddb9a96..445fa1761b9 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{InferCtxt, InferOk};
 use rustc_middle::bug;
 use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt, Upcast};
 use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_span::Span;
 use smallvec::{smallvec, SmallVec};
@@ -105,7 +105,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
     fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
         let tcx = self.tcx;
         let trait_ref = item.trait_ref();
-        let pred = trait_ref.to_predicate(tcx);
+        let pred = trait_ref.upcast(tcx);
 
         debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
 
@@ -122,7 +122,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
             .iter()
             .rev()
             .skip(1)
-            .any(|&(tr, _)| anonymize_predicate(tcx, tr.to_predicate(tcx)) == anon_pred)
+            .any(|&(tr, _)| anonymize_predicate(tcx, tr.upcast(tcx)) == anon_pred)
         {
             return false;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 8fd9889b4ea..c93ec43944a 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -9,7 +9,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
+use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry};
 use rustc_span::{sym, Span};
 use smallvec::{smallvec, SmallVec};
 
@@ -87,7 +87,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
 
     let mut emit_vptr_on_new_entry = false;
     let mut visited = PredicateSet::new(tcx);
-    let predicate = trait_ref.to_predicate(tcx);
+    let predicate = trait_ref.upcast(tcx);
     let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
         smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))];
     visited.insert(predicate);
@@ -130,7 +130,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
 
             // Find an unvisited supertrait
             match direct_super_traits_iter
-                .find(|&super_trait| visited.insert(super_trait.to_predicate(tcx)))
+                .find(|&super_trait| visited.insert(super_trait.upcast(tcx)))
             {
                 // Push it to the stack for the next iteration of 'diving_in to pick up
                 Some(unvisited_super_trait) => {
@@ -165,7 +165,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
             }
 
             if let Some(next_inner_most_trait_ref) =
-                siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx)))
+                siblings.find(|&sibling| visited.insert(sibling.upcast(tcx)))
             {
                 // We're throwing away potential constness of super traits here.
                 // FIXME: handle ~const super traits
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 6d84523da8a..f4189ff0902 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -377,7 +377,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         let item = self.item;
 
         let extend = |traits::PredicateObligation { predicate, mut cause, .. }| {
-            if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() {
+            if let Some(parent_trait_pred) = predicate.as_trait_clause() {
                 cause = cause.derived_cause(
                     parent_trait_pred,
                     traits::ObligationCauseCode::WellFormedDerived,
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index fd7e2fec389..9090bb30f89 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -37,7 +37,7 @@ fn fn_sig_for_fn_abi<'tcx>(
             [],
             tcx.thread_local_ptr_ty(instance.def_id()),
             false,
-            hir::Unsafety::Normal,
+            hir::Safety::Safe,
             rustc_target::spec::abi::Abi::Unadjusted,
         ));
     }
@@ -96,7 +96,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                     iter::once(env_ty).chain(sig.inputs().iter().cloned()),
                     sig.output(),
                     sig.c_variadic,
-                    sig.unsafety,
+                    sig.safety,
                     sig.abi,
                 ),
                 bound_vars,
@@ -150,7 +150,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                         args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
                     ),
                     sig.c_variadic,
-                    sig.unsafety,
+                    sig.safety,
                     sig.abi,
                 ),
                 bound_vars,
@@ -301,7 +301,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                     [env_ty, resume_ty],
                     ret_ty,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     rustc_target::spec::abi::Abi::Rust,
                 )
             } else {
@@ -310,7 +310,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                     [env_ty],
                     ret_ty,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     rustc_target::spec::abi::Abi::Rust,
                 )
             };
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 492cc1d55cb..3094956fa5f 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -6,7 +6,7 @@ use rustc_index::bit_set::BitSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt, TypeVisitor};
-use rustc_middle::ty::{ToPredicate, TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, Upcast};
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits;
@@ -220,7 +220,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
                     },
                     self.bound_vars,
                 )
-                .to_predicate(self.tcx),
+                .upcast(self.tcx),
             );
 
             // We walk the *un-shifted* alias ty, because we're tracking the de bruijn
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index efefd174cd6..1c30f03c693 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -1,11 +1,12 @@
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt;
 use std::hash::Hash;
+use std::ops::Index;
 
 use crate::inherent::*;
-use crate::{Interner, UniverseIndex};
+use crate::{self as ty, Interner, UniverseIndex};
 
 /// A "canonicalized" type `V` is one where all free inference
 /// variables have been rewritten to "canonical vars". These are
@@ -257,3 +258,139 @@ pub enum CanonicalTyVarKind {
     /// Floating-point type variable `?F` (that can only be unified with float types).
     Float,
 }
+
+/// A set of values corresponding to the canonical variables from some
+/// `Canonical`. You can give these values to
+/// `canonical_value.instantiate` to instantiate them into the canonical
+/// value at the right places.
+///
+/// When you canonicalize a value `V`, you get back one of these
+/// vectors with the original values that were replaced by canonical
+/// variables. You will need to supply it later to instantiate the
+/// canonicalized query response.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Hash(bound = ""),
+    Debug(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+pub struct CanonicalVarValues<I: Interner> {
+    pub var_values: I::GenericArgs,
+}
+
+impl<I: Interner> CanonicalVarValues<I> {
+    pub fn is_identity(&self) -> bool {
+        self.var_values.into_iter().enumerate().all(|(bv, arg)| match arg.kind() {
+            ty::GenericArgKind::Lifetime(r) => {
+                matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv)
+            }
+            ty::GenericArgKind::Type(ty) => {
+                matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv)
+            }
+            ty::GenericArgKind::Const(ct) => {
+                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv)
+            }
+        })
+    }
+
+    pub fn is_identity_modulo_regions(&self) -> bool {
+        let mut var = ty::BoundVar::ZERO;
+        for arg in self.var_values {
+            match arg.kind() {
+                ty::GenericArgKind::Lifetime(r) => {
+                    if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) {
+                        var = var + 1;
+                    } else {
+                        // It's ok if this region var isn't an identity variable
+                    }
+                }
+                ty::GenericArgKind::Type(ty) => {
+                    if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) {
+                        var = var + 1;
+                    } else {
+                        return false;
+                    }
+                }
+                ty::GenericArgKind::Const(ct) => {
+                    if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var())
+                    {
+                        var = var + 1;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        true
+    }
+
+    // Given a list of canonical variables, construct a set of values which are
+    // the identity response.
+    pub fn make_identity(tcx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> {
+        CanonicalVarValues {
+            var_values: tcx.mk_args_from_iter(infos.into_iter().enumerate().map(
+                |(i, info)| -> I::GenericArg {
+                    match info.kind {
+                        CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
+                            Ty::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i))
+                                .into()
+                        }
+                        CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
+                            Region::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i))
+                                .into()
+                        }
+                        CanonicalVarKind::Effect => Const::new_anon_bound(
+                            tcx,
+                            ty::INNERMOST,
+                            ty::BoundVar::from_usize(i),
+                            Ty::new_bool(tcx),
+                        )
+                        .into(),
+                        CanonicalVarKind::Const(_, ty)
+                        | CanonicalVarKind::PlaceholderConst(_, ty) => Const::new_anon_bound(
+                            tcx,
+                            ty::INNERMOST,
+                            ty::BoundVar::from_usize(i),
+                            ty,
+                        )
+                        .into(),
+                    }
+                },
+            )),
+        }
+    }
+
+    /// Creates dummy var values which should not be used in a
+    /// canonical response.
+    pub fn dummy() -> CanonicalVarValues<I> {
+        CanonicalVarValues { var_values: Default::default() }
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.var_values.len()
+    }
+}
+
+impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> {
+    type Item = I::GenericArg;
+    type IntoIter = <I::GenericArgs as IntoIterator>::IntoIter;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.var_values.into_iter()
+    }
+}
+
+impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
+    type Output = I::GenericArg;
+
+    fn index(&self, value: ty::BoundVar) -> &I::GenericArg {
+        &self.var_values[value.as_usize()]
+    }
+}
diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs
new file mode 100644
index 00000000000..622a4080608
--- /dev/null
+++ b/compiler/rustc_type_ir/src/generic_arg.rs
@@ -0,0 +1,18 @@
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+
+use crate::Interner;
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Debug(bound = ""),
+    Eq(bound = ""),
+    PartialEq(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum GenericArgKind<I: Interner> {
+    Lifetime(I::Region),
+    Type(I::Ty),
+    Const(I::Const),
+}
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 92b1e08ab0a..5289dfd932f 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -1,3 +1,8 @@
+//! Set of traits which are used to emulate the inherent impls that are present in `rustc_middle`.
+//! It is customary to glob-import `rustc_type_ir::inherent::*` to bring all of these traits into
+//! scope when programming in interner-agnostic settings, and to avoid importing any of these
+//! directly elsewhere (i.e. specify the full path for an implementation downstream).
+
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Deref;
@@ -21,11 +26,28 @@ pub trait Ty<I: Interner<Ty = Self>>:
     + TypeSuperFoldable<I>
     + Flags
 {
+    fn new_bool(interner: I) -> Self;
+
     fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
 
     fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
 }
 
+pub trait Tys<I: Interner<Tys = Self>>:
+    Copy + Debug + Hash + Eq + IntoIterator<Item = I::Ty> + Deref<Target: Deref<Target = [I::Ty]>>
+{
+    fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty);
+}
+
+pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq {
+    /// Whether this ABI is `extern "Rust"`.
+    fn is_rust(self) -> bool;
+}
+
+pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq {
+    fn prefix_str(self) -> &'static str;
+}
+
 pub trait Region<I: Interner<Region = Self>>:
     Copy + DebugWithInfcx<I> + Hash + Eq + Into<I::GenericArg> + IntoKind<Kind = RegionKind<I>> + Flags
 {
@@ -64,6 +86,7 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
     + Eq
     + IntoIterator<Item = I::GenericArg>
     + Deref<Target: Deref<Target = [I::GenericArg]>>
+    + Default
 {
     fn type_at(self, i: usize) -> I::Ty;
 
@@ -96,3 +119,7 @@ pub trait BoundVars<I: Interner> {
 
     fn has_no_bound_vars(&self) -> bool;
 }
+
+pub trait BoundVarLike<I: Interner> {
+    fn var(self) -> BoundVar;
+}
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index d6680977168..9acf7c04dd6 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -1,14 +1,16 @@
 use smallvec::SmallVec;
 use std::fmt::Debug;
 use std::hash::Hash;
+use std::ops::Deref;
 
 use crate::inherent::*;
 use crate::ir_print::IrPrint;
+use crate::solve::inspect::GoalEvaluationStep;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{
     AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
-    DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate,
-    SubtypePredicate, TraitPredicate, TraitRef,
+    DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, GenericArgKind,
+    NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
 };
 
 pub trait Interner:
@@ -24,14 +26,16 @@ pub trait Interner:
     + IrPrint<NormalizesTo<Self>>
     + IrPrint<SubtypePredicate<Self>>
     + IrPrint<CoercePredicate<Self>>
+    + IrPrint<FnSig<Self>>
 {
     type DefId: Copy + Debug + Hash + Eq;
-    type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
     type AdtDef: Copy + Debug + Hash + Eq;
 
     type GenericArgs: GenericArgs<Self>;
-    type GenericArgsSlice: Copy + Debug + Hash + Eq;
-    type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq;
+    /// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`,
+    /// not including the args from the parent item (trait or impl).
+    type OwnItemArgs: Copy + Debug + Hash + Eq;
+    type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq + IntoKind<Kind = GenericArgKind<Self>>;
     type Term: Copy + Debug + Hash + Eq;
 
     type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
@@ -39,12 +43,17 @@ pub trait Interner:
     type BoundVar;
 
     type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
+    type PredefinedOpaques: Copy + Debug + Hash + Eq;
+    type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
+    type ExternalConstraints: Copy + Debug + Hash + Eq;
+    type GoalEvaluationSteps: Copy + Debug + Hash + Eq + Deref<Target = [GoalEvaluationStep<Self>]>;
 
     // Kinds of tys
     type Ty: Ty<Self>;
-    type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
+    type Tys: Tys<Self>;
+    type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]>;
     type ParamTy: Copy + Debug + Hash + Eq;
-    type BoundTy: Copy + Debug + Hash + Eq;
+    type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type PlaceholderTy: PlaceholderLike;
 
     // Things stored inside of tys
@@ -53,13 +62,15 @@ pub trait Interner:
     type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type AllocId: Copy + Debug + Hash + Eq;
     type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>;
+    type Safety: Safety<Self>;
+    type Abi: Abi<Self>;
 
     // Kinds of consts
     type Const: Const<Self>;
     type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type PlaceholderConst: PlaceholderLike;
     type ParamConst: Copy + Debug + Hash + Eq;
-    type BoundConst: Copy + Debug + Hash + Eq;
+    type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type ValueConst: Copy + Debug + Hash + Eq;
     type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
 
@@ -67,11 +78,12 @@ pub trait Interner:
     type Region: Region<Self>;
     type EarlyParamRegion: Copy + Debug + Hash + Eq;
     type LateParamRegion: Copy + Debug + Hash + Eq;
-    type BoundRegion: Copy + Debug + Hash + Eq;
+    type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type PlaceholderRegion: PlaceholderLike;
 
     // Predicates
+    type ParamEnv: Copy + Debug + Hash + Eq;
     type Predicate: Predicate<Self>;
     type TraitPredicate: Copy + Debug + Hash + Eq;
     type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
@@ -99,7 +111,7 @@ pub trait Interner:
         self,
         def_id: Self::DefId,
         args: Self::GenericArgs,
-    ) -> (TraitRef<Self>, Self::GenericArgsSlice);
+    ) -> (TraitRef<Self>, Self::OwnItemArgs);
 
     fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
 
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
index 2a766d0bc09..af4b9eef14b 100644
--- a/compiler/rustc_type_ir/src/ir_print.rs
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -1,8 +1,8 @@
 use std::fmt;
 
 use crate::{
-    AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner,
-    NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
+    AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
+    Interner, NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
 };
 
 pub trait IrPrint<T> {
@@ -45,6 +45,7 @@ define_display_via_print!(
     CoercePredicate,
     AliasTy,
     AliasTerm,
+    FnSig,
 );
 
 define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 4560a54da82..fa9bda9a2f7 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -19,13 +19,13 @@ use std::sync::Arc as Lrc;
 
 #[macro_use]
 pub mod visit;
-
 #[cfg(feature = "nightly")]
 pub mod codec;
 pub mod fold;
 pub mod inherent;
 pub mod ir_print;
 pub mod lift;
+pub mod solve;
 pub mod ty_info;
 pub mod ty_kind;
 
@@ -35,11 +35,13 @@ mod canonical;
 mod const_kind;
 mod debug;
 mod flags;
+mod generic_arg;
 mod infcx;
 mod interner;
 mod predicate;
 mod predicate_kind;
 mod region_kind;
+mod upcast;
 
 pub use canonical::*;
 #[cfg(feature = "nightly")]
@@ -47,6 +49,7 @@ pub use codec::*;
 pub use const_kind::*;
 pub use debug::{DebugWithInfcx, WithInfcx};
 pub use flags::*;
+pub use generic_arg::*;
 pub use infcx::InferCtxtLike;
 pub use interner::*;
 pub use predicate::*;
@@ -54,6 +57,7 @@ pub use predicate_kind::*;
 pub use region_kind::*;
 pub use ty_info::*;
 pub use ty_kind::*;
+pub use upcast::*;
 pub use AliasTyKind::*;
 pub use DynKind::*;
 pub use InferTy::*;
@@ -366,6 +370,12 @@ rustc_index::newtype_index! {
     pub struct BoundVar {}
 }
 
+impl<I: Interner> inherent::BoundVarLike<I> for BoundVar {
+    fn var(self) -> BoundVar {
+        self
+    }
+}
+
 /// Represents the various closure traits in the language. This
 /// will determine the type of the environment (`self`, in the
 /// desugaring) argument that the closure expects.
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index b6c7c2c348c..c0619d782c6 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -1,4 +1,5 @@
 use std::fmt;
+use std::hash::Hash;
 
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
@@ -497,7 +498,7 @@ impl<I: Interner> AliasTerm<I> {
     /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
     /// then this function would return a `T: StreamingIterator` trait reference and
     /// `['a]` as the own args.
-    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
+    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::OwnItemArgs) {
         interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
     }
 
diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs
new file mode 100644
index 00000000000..3c24e851d7b
--- /dev/null
+++ b/compiler/rustc_type_ir/src/solve.rs
@@ -0,0 +1,278 @@
+pub mod inspect;
+
+use std::fmt;
+use std::hash::Hash;
+
+#[cfg(feature = "nightly")]
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+
+use crate::{Canonical, CanonicalVarValues, Interner, Upcast};
+
+pub type CanonicalInput<I, T = <I as Interner>::Predicate> = Canonical<I, QueryInput<I, T>>;
+pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
+/// The result of evaluating a canonical query.
+///
+/// FIXME: We use a different type than the existing canonical queries. This is because
+/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
+/// having to worry about changes to currently used code. Once we've made progress on this
+/// solver, merge the two responses again.
+pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>;
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(TypeFoldable_Generic, TypeVisitable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub struct NoSolution;
+
+/// A goal is a statement, i.e. `predicate`, we want to prove
+/// given some assumptions, i.e. `param_env`.
+///
+/// Most of the time the `param_env` contains the `where`-bounds of the function
+/// we're currently typechecking while the `predicate` is some trait bound.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "P: Clone"),
+    Copy(bound = "P: Copy"),
+    Hash(bound = "P: Hash"),
+    PartialEq(bound = "P: PartialEq"),
+    Eq(bound = "P: Eq"),
+    Debug(bound = "P: fmt::Debug")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct Goal<I: Interner, P> {
+    pub param_env: I::ParamEnv,
+    pub predicate: P,
+}
+
+impl<I: Interner, P> Goal<I, P> {
+    pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> {
+        Goal { param_env, predicate: predicate.upcast(tcx) }
+    }
+
+    /// Updates the goal to one with a different `predicate` but the same `param_env`.
+    pub fn with<Q>(self, tcx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> {
+        Goal { param_env: self.param_env, predicate: predicate.upcast(tcx) }
+    }
+}
+
+/// Why a specific goal has to be proven.
+///
+/// This is necessary as we treat nested goals different depending on
+/// their source.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum GoalSource {
+    Misc,
+    /// We're proving a where-bound of an impl.
+    ///
+    /// FIXME(-Znext-solver=coinductive): Explain how and why this
+    /// changes whether cycles are coinductive.
+    ///
+    /// This also impacts whether we erase constraints on overflow.
+    /// Erasing constraints is generally very useful for perf and also
+    /// results in better error messages by avoiding spurious errors.
+    /// We do not erase overflow constraints in `normalizes-to` goals unless
+    /// they are from an impl where-clause. This is necessary due to
+    /// backwards compatability, cc trait-system-refactor-initiatitive#70.
+    ImplWhereBound,
+    /// Instantiating a higher-ranked goal and re-proving it.
+    InstantiateHigherRanked,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "Goal<I, P>: Clone"),
+    Copy(bound = "Goal<I, P>: Copy"),
+    Hash(bound = "Goal<I, P>: Hash"),
+    PartialEq(bound = "Goal<I, P>: PartialEq"),
+    Eq(bound = "Goal<I, P>: Eq"),
+    Debug(bound = "Goal<I, P>: fmt::Debug")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct QueryInput<I: Interner, P> {
+    pub goal: Goal<I, P>,
+    pub predefined_opaques_in_body: I::PredefinedOpaques,
+}
+
+/// Possible ways the given goal can be proven.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = "")
+)]
+pub enum CandidateSource<I: Interner> {
+    /// A user written impl.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     let x: Vec<u32> = Vec::new();
+    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
+    ///     let y = x.clone();
+    /// }
+    /// ```
+    Impl(I::DefId),
+    /// A builtin impl generated by the compiler. When adding a new special
+    /// trait, try to use actual impls whenever possible. Builtin impls should
+    /// only be used in cases where the impl cannot be manually be written.
+    ///
+    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
+    /// For a list of all traits with builtin impls, check out the
+    /// `EvalCtxt::assemble_builtin_impl_candidates` method.
+    BuiltinImpl(BuiltinImplSource),
+    /// An assumption from the environment.
+    ///
+    /// More precisely we've used the `n-th` assumption in the `param_env`.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn is_clone<T: Clone>(x: T) -> (T, T) {
+    ///     // This uses the assumption `T: Clone` from the `where`-bounds
+    ///     // to prove `T: Clone`.
+    ///     (x.clone(), x)
+    /// }
+    /// ```
+    ParamEnv(usize),
+    /// If the self type is an alias type, e.g. an opaque type or a projection,
+    /// we know the bounds on that alias to hold even without knowing its concrete
+    /// underlying type.
+    ///
+    /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
+    /// the self type.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// trait Trait {
+    ///     type Assoc: Clone;
+    /// }
+    ///
+    /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
+    ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
+    ///     // in the trait definition.
+    ///     let _y = x.clone();
+    /// }
+    /// ```
+    AliasBound,
+    /// A candidate that is registered only during coherence to represent some
+    /// yet-unknown impl that could be produced downstream without violating orphan
+    /// rules.
+    // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
+    CoherenceUnknowable,
+}
+
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))]
+pub enum BuiltinImplSource {
+    /// Some builtin impl we don't need to differentiate. This should be used
+    /// unless more specific information is necessary.
+    Misc,
+    /// A builtin impl for trait objects.
+    ///
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
+    /// in that vtable.
+    Object { vtable_base: usize },
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
+    /// within that vtable.
+    TraitUpcasting { vtable_vptr_slot: Option<usize> },
+    /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
+    ///
+    /// This needs to be a separate variant as it is still unstable and we need to emit
+    /// a feature error when using it on stable.
+    TupleUnsizing,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub struct Response<I: Interner> {
+    pub certainty: Certainty,
+    pub var_values: CanonicalVarValues<I>,
+    /// Additional constraints returned by this query.
+    pub external_constraints: I::ExternalConstraints,
+}
+
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum Certainty {
+    Yes,
+    Maybe(MaybeCause),
+}
+
+impl Certainty {
+    pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
+
+    /// Use this function to merge the certainty of multiple nested subgoals.
+    ///
+    /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested
+    /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`.
+    /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in
+    /// success, we merge these two responses. This results in ambiguity.
+    ///
+    /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
+    /// inside of the solver as we do not distinguish ambiguity from overflow. It does
+    /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
+    /// in ambiguity without changing the inference state, we still want to tell the
+    /// user that `T: Baz` results in overflow.
+    pub fn unify_with(self, other: Certainty) -> Certainty {
+        match (self, other) {
+            (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
+            (Certainty::Yes, Certainty::Maybe(_)) => other,
+            (Certainty::Maybe(_), Certainty::Yes) => self,
+            (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
+        }
+    }
+
+    pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
+        Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
+    }
+}
+
+/// Why we failed to evaluate a goal.
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum MaybeCause {
+    /// We failed due to ambiguity. This ambiguity can either
+    /// be a true ambiguity, i.e. there are multiple different answers,
+    /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
+    Ambiguity,
+    /// We gave up due to an overflow, most often by hitting the recursion limit.
+    Overflow { suggest_increasing_limit: bool },
+}
+
+impl MaybeCause {
+    fn unify_with(self, other: MaybeCause) -> MaybeCause {
+        match (self, other) {
+            (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
+            (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
+            (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
+            (
+                MaybeCause::Overflow { suggest_increasing_limit: a },
+                MaybeCause::Overflow { suggest_increasing_limit: b },
+            ) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
index 9e944899026..c4f6ee2669b 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -18,16 +18,19 @@
 //!
 //! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
 
-use super::{
-    CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, NoSolution,
-    QueryInput, QueryResult,
-};
-use crate::{infer::canonical::CanonicalVarValues, ty};
-use format::ProofTreeFormatter;
-use rustc_macros::{TypeFoldable, TypeVisitable};
+mod format;
+
 use std::fmt::{Debug, Write};
+use std::hash::Hash;
 
-mod format;
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+
+use self::format::ProofTreeFormatter;
+use crate::solve::{
+    CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, NoSolution, QueryInput,
+    QueryResult,
+};
+use crate::{Canonical, CanonicalVarValues, Interner};
 
 /// Some `data` together with information about how they relate to the input
 /// of the canonical query.
@@ -35,96 +38,113 @@ mod format;
 /// This is only ever used as [CanonicalState]. Any type information in proof
 /// trees used mechanically has to be canonicalized as we otherwise leak
 /// inference variables from a nested `InferCtxt`.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, TypeFoldable, TypeVisitable)]
-pub struct State<'tcx, T> {
-    pub var_values: CanonicalVarValues<'tcx>,
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "T: Clone"),
+    Copy(bound = "T: Copy"),
+    PartialEq(bound = "T: PartialEq"),
+    Eq(bound = "T: Eq"),
+    Hash(bound = "T: Hash"),
+    Debug(bound = "T: Debug")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+pub struct State<I: Interner, T> {
+    pub var_values: CanonicalVarValues<I>,
     pub data: T,
 }
 
-pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>;
+pub type CanonicalState<I, T> = Canonical<I, State<I, T>>;
 
 /// When evaluating the root goals we also store the
 /// original values for the `CanonicalVarValues` of the
 /// canonicalized goal. We use this to map any [CanonicalState]
 /// from the local `InferCtxt` of the solver query to
 /// the `InferCtxt` of the caller.
-#[derive(Eq, PartialEq)]
-pub enum GoalEvaluationKind<'tcx> {
-    Root { orig_values: Vec<ty::GenericArg<'tcx>> },
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub enum GoalEvaluationKind<I: Interner> {
+    Root { orig_values: Vec<I::GenericArg> },
     Nested,
 }
 
-#[derive(Eq, PartialEq)]
-pub struct GoalEvaluation<'tcx> {
-    pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    pub kind: GoalEvaluationKind<'tcx>,
-    pub evaluation: CanonicalGoalEvaluation<'tcx>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))]
+pub struct GoalEvaluation<I: Interner> {
+    pub uncanonicalized_goal: Goal<I, I::Predicate>,
+    pub kind: GoalEvaluationKind<I>,
+    pub evaluation: CanonicalGoalEvaluation<I>,
 }
 
-#[derive(Eq, PartialEq, Debug)]
-pub struct CanonicalGoalEvaluation<'tcx> {
-    pub goal: CanonicalInput<'tcx>,
-    pub kind: CanonicalGoalEvaluationKind<'tcx>,
-    pub result: QueryResult<'tcx>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub struct CanonicalGoalEvaluation<I: Interner> {
+    pub goal: CanonicalInput<I>,
+    pub kind: CanonicalGoalEvaluationKind<I>,
+    pub result: QueryResult<I>,
 }
 
-#[derive(Eq, PartialEq, Debug)]
-pub enum CanonicalGoalEvaluationKind<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub enum CanonicalGoalEvaluationKind<I: Interner> {
     Overflow,
     CycleInStack,
     ProvisionalCacheHit,
-    Evaluation { revisions: &'tcx [GoalEvaluationStep<'tcx>] },
+    Evaluation { revisions: I::GoalEvaluationSteps },
 }
-impl Debug for GoalEvaluation<'_> {
+impl<I: Interner> Debug for GoalEvaluation<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         ProofTreeFormatter::new(f).format_goal_evaluation(self)
     }
 }
 
-#[derive(Eq, PartialEq)]
-pub struct AddedGoalsEvaluation<'tcx> {
-    pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub struct AddedGoalsEvaluation<I: Interner> {
+    pub evaluations: Vec<Vec<GoalEvaluation<I>>>,
     pub result: Result<Certainty, NoSolution>,
 }
 
-#[derive(Eq, PartialEq, Debug)]
-pub struct GoalEvaluationStep<'tcx> {
-    pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub struct GoalEvaluationStep<I: Interner> {
+    pub instantiated_goal: QueryInput<I, I::Predicate>,
 
     /// The actual evaluation of the goal, always `ProbeKind::Root`.
-    pub evaluation: Probe<'tcx>,
+    pub evaluation: Probe<I>,
 }
 
 /// A self-contained computation during trait solving. This either
 /// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
 /// of a goal.
-#[derive(Eq, PartialEq)]
-pub struct Probe<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))]
+pub struct Probe<I: Interner> {
     /// What happened inside of this probe in chronological order.
-    pub steps: Vec<ProbeStep<'tcx>>,
-    pub kind: ProbeKind<'tcx>,
-    pub final_state: CanonicalState<'tcx, ()>,
+    pub steps: Vec<ProbeStep<I>>,
+    pub kind: ProbeKind<I>,
+    pub final_state: CanonicalState<I, ()>,
 }
 
-impl Debug for Probe<'_> {
+impl<I: Interner> Debug for Probe<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         ProofTreeFormatter::new(f).format_probe(self)
     }
 }
 
-#[derive(Eq, PartialEq)]
-pub enum ProbeStep<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub enum ProbeStep<I: Interner> {
     /// We added a goal to the `EvalCtxt` which will get proven
     /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
-    AddGoal(GoalSource, CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
+    AddGoal(GoalSource, CanonicalState<I, Goal<I, I::Predicate>>),
     /// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
-    EvaluateGoals(AddedGoalsEvaluation<'tcx>),
+    EvaluateGoals(AddedGoalsEvaluation<I>),
     /// A call to `probe` while proving the current goal. This is
     /// used whenever there are multiple candidates to prove the
     /// current goalby .
-    NestedProbe(Probe<'tcx>),
+    NestedProbe(Probe<I>),
     /// A trait goal was satisfied by an impl candidate.
-    RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
+    RecordImplArgs { impl_args: CanonicalState<I, I::GenericArgs> },
     /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with
     /// `Certainty` was made. This is the certainty passed in, so it's not unified
     /// with the certainty of the `try_evaluate_added_goals` that is done within;
@@ -136,16 +156,25 @@ pub enum ProbeStep<'tcx> {
 /// What kind of probe we're in. In case the probe represents a candidate, or
 /// the final result of the current goal - via [ProbeKind::Root] - we also
 /// store the [QueryResult].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum ProbeKind<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Hash(bound = ""),
+    Debug(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+pub enum ProbeKind<I: Interner> {
     /// The root inference context while proving a goal.
-    Root { result: QueryResult<'tcx> },
+    Root { result: QueryResult<I> },
     /// Trying to normalize an alias by at least one step in `NormalizesTo`.
-    TryNormalizeNonRigid { result: QueryResult<'tcx> },
+    TryNormalizeNonRigid { result: QueryResult<I> },
     /// Probe entered when normalizing the self ty during candidate assembly
     NormalizedSelfTyAssembly,
     /// A candidate for proving a trait or alias-relate goal.
-    TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
+    TraitCandidate { source: CandidateSource<I>, result: QueryResult<I> },
     /// Used in the probe that wraps normalizing the non-self type for the unsize
     /// trait, which is also structurally matched on.
     UnsizeAssembly,
@@ -156,5 +185,5 @@ pub enum ProbeKind<'tcx> {
     /// Looking for param-env candidates that satisfy the trait ref for a projection.
     ShadowedEnvProbing,
     /// Try to unify an opaque type with an existing key in the storage.
-    OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
+    OpaqueTypeStorageLookup { result: QueryResult<I> },
 }
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_type_ir/src/solve/inspect/format.rs
index 5b3c50cb973..44ade04cf98 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect/format.rs
@@ -1,7 +1,10 @@
+use std::marker::PhantomData;
+
 use super::*;
 
-pub(super) struct ProofTreeFormatter<'a, 'b> {
+pub(super) struct ProofTreeFormatter<'a, 'b, I> {
     f: &'a mut (dyn Write + 'b),
+    _interner: PhantomData<I>,
 }
 
 enum IndentorState {
@@ -36,23 +39,24 @@ impl Write for Indentor<'_, '_> {
     }
 }
 
-impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
+impl<'a, 'b, I: Interner> ProofTreeFormatter<'a, 'b, I> {
     pub(super) fn new(f: &'a mut (dyn Write + 'b)) -> Self {
-        ProofTreeFormatter { f }
+        ProofTreeFormatter { f, _interner: PhantomData }
     }
 
     fn nested<F>(&mut self, func: F) -> std::fmt::Result
     where
-        F: FnOnce(&mut ProofTreeFormatter<'_, '_>) -> std::fmt::Result,
+        F: FnOnce(&mut ProofTreeFormatter<'_, '_, I>) -> std::fmt::Result,
     {
         write!(self.f, " {{")?;
         func(&mut ProofTreeFormatter {
             f: &mut Indentor { f: self.f, state: IndentorState::StartWithNewline },
+            _interner: PhantomData,
         })?;
         writeln!(self.f, "}}")
     }
 
-    pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
+    pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<I>) -> std::fmt::Result {
         let goal_text = match eval.kind {
             GoalEvaluationKind::Root { orig_values: _ } => "ROOT GOAL",
             GoalEvaluationKind::Nested => "GOAL",
@@ -63,7 +67,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
 
     pub(super) fn format_canonical_goal_evaluation(
         &mut self,
-        eval: &CanonicalGoalEvaluation<'_>,
+        eval: &CanonicalGoalEvaluation<I>,
     ) -> std::fmt::Result {
         writeln!(self.f, "GOAL: {:?}", eval.goal)?;
 
@@ -89,13 +93,13 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
 
     pub(super) fn format_evaluation_step(
         &mut self,
-        evaluation_step: &GoalEvaluationStep<'_>,
+        evaluation_step: &GoalEvaluationStep<I>,
     ) -> std::fmt::Result {
         writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
         self.format_probe(&evaluation_step.evaluation)
     }
 
-    pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
+    pub(super) fn format_probe(&mut self, probe: &Probe<I>) -> std::fmt::Result {
         match &probe.kind {
             ProbeKind::Root { result } => {
                 write!(self.f, "ROOT RESULT: {result:?}")
@@ -150,7 +154,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
 
     pub(super) fn format_added_goals_evaluation(
         &mut self,
-        added_goals_evaluation: &AddedGoalsEvaluation<'_>,
+        added_goals_evaluation: &AddedGoalsEvaluation<I>,
     ) -> std::fmt::Result {
         writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", added_goals_evaluation.result)?;
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 672c890f94e..629ea9fb839 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -342,7 +342,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
 impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
     fn fmt<Infcx: InferCtxtLike<Interner = I>>(
         this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
+        f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         match this.data {
             Bool => write!(f, "bool"),
@@ -514,7 +514,7 @@ impl<I: Interner> AliasTy<I> {
     /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
     /// then this function would return a `T: StreamingIterator` trait reference and
     /// `['a]` as the own args.
-    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
+    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::OwnItemArgs) {
         debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
         interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
     }
@@ -561,8 +561,8 @@ impl<I: Interner> fmt::Debug for AliasTy<I> {
 impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
     fn fmt<Infcx: InferCtxtLike<Interner = I>>(
         this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
         f.debug_struct("AliasTy")
             .field("args", &this.map(|data| data.args))
             .field("def_id", &this.data.def_id)
@@ -952,3 +952,76 @@ pub struct TypeAndMut<I: Interner> {
     pub ty: I::Ty,
     pub mutbl: Mutability,
 }
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Hash(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+pub struct FnSig<I: Interner> {
+    pub inputs_and_output: I::Tys,
+    pub c_variadic: bool,
+    pub safety: I::Safety,
+    pub abi: I::Abi,
+}
+
+impl<I: Interner> FnSig<I> {
+    pub fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty) {
+        self.inputs_and_output.split_inputs_and_output()
+    }
+
+    pub fn inputs(self) -> I::FnInputTys {
+        self.split_inputs_and_output().0
+    }
+
+    pub fn output(self) -> I::Ty {
+        self.split_inputs_and_output().1
+    }
+}
+
+impl<I: Interner> fmt::Debug for FnSig<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
+        let sig = this.data;
+        let FnSig { inputs_and_output: _, c_variadic, safety, abi } = sig;
+
+        write!(f, "{}", safety.prefix_str())?;
+        if !abi.is_rust() {
+            write!(f, "extern \"{abi:?}\" ")?;
+        }
+
+        write!(f, "fn(")?;
+        let (inputs, output) = sig.split_inputs_and_output();
+        for (i, ty) in inputs.iter().enumerate() {
+            if i > 0 {
+                write!(f, ", ")?;
+            }
+            write!(f, "{:?}", &this.wrap(ty))?;
+        }
+        if *c_variadic {
+            if inputs.is_empty() {
+                write!(f, "...")?;
+            } else {
+                write!(f, ", ...")?;
+            }
+        }
+        write!(f, ")")?;
+
+        match output.kind() {
+            Tuple(list) if list.is_empty() => Ok(()),
+            _ => write!(f, " -> {:?}", &this.wrap(sig.output())),
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/upcast.rs b/compiler/rustc_type_ir/src/upcast.rs
new file mode 100644
index 00000000000..2049337c351
--- /dev/null
+++ b/compiler/rustc_type_ir/src/upcast.rs
@@ -0,0 +1,24 @@
+/// An `Into`-like trait that takes `TyCtxt` to perform interner-specific transformations.
+pub trait Upcast<I, T> {
+    fn upcast(self, interner: I) -> T;
+}
+
+impl<I, T, U> Upcast<I, U> for T
+where
+    U: UpcastFrom<I, T>,
+{
+    fn upcast(self, interner: I) -> U {
+        U::upcast_from(self, interner)
+    }
+}
+
+/// A `From`-like trait that takes `TyCtxt` to perform interner-specific transformations.
+pub trait UpcastFrom<I, T> {
+    fn upcast_from(from: T, interner: I) -> Self;
+}
+
+impl<I, T> UpcastFrom<I, T> for T {
+    fn upcast_from(from: T, _tcx: I) -> Self {
+        from
+    }
+}
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index e077c580318..a1432acf93c 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -915,8 +915,8 @@ pub enum Mutability {
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum Safety {
+    Safe,
     Unsafe,
-    Normal,
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 56251613840..759e3f166bd 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1,6 +1,5 @@
 use super::{
-    mir::Safety,
-    mir::{Body, Mutability},
+    mir::{Body, Mutability, Safety},
     with, DefId, Error, Symbol,
 };
 use crate::abi::Layout;
@@ -909,7 +908,7 @@ pub type PolyFnSig = Binder<FnSig>;
 pub struct FnSig {
     pub inputs_and_output: Vec<Ty>,
     pub c_variadic: bool,
-    pub unsafety: Safety,
+    pub safety: Safety,
     pub abi: Abi,
 }
 
@@ -1200,7 +1199,7 @@ pub enum TraitSpecializationKind {
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct TraitDecl {
     pub def_id: TraitDef,
-    pub unsafety: Safety,
+    pub safety: Safety,
     pub paren_sugar: bool,
     pub has_auto_impl: bool,
     pub is_marker: bool,
diff --git a/config.example.toml b/config.example.toml
index 224d079b206..228521747ed 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -653,9 +653,12 @@
 # when no explicit backend is specified.
 #codegen-backends = ["llvm"]
 
-# Indicates whether LLD will be compiled and made available in the sysroot for
-# rustc to execute.
-#lld = false
+# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and
+# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be
+# when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from
+# the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will
+# make this default to false. 
+#lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true
 
 # Indicates whether LLD will be used to link Rust crates during bootstrap on
 # supported platforms.
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index e5d62447eb2..f1a6df94e11 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -2081,6 +2081,54 @@ impl<I> FromIterator<I> for Box<[I]> {
 }
 
 #[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl FromIterator<char> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a> FromIterator<&'a char> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a> FromIterator<&'a str> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl FromIterator<String> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
     fn clone(&self) -> Self {
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 2a859ad55ee..36078da7c35 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -60,6 +60,8 @@ use core::slice;
 use core::str::pattern::Pattern;
 
 #[cfg(not(no_global_oom_handling))]
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::collections::TryReserveError;
@@ -1940,8 +1942,10 @@ impl String {
 
     /// Converts this `String` into a <code>[Box]<[str]></code>.
     ///
-    /// This will drop any excess capacity.
+    /// Before doing the conversion, this method discards excess capacity like [`shrink_to_fit`].
+    /// Note that this call may reallocate and copy the bytes of the string.
     ///
+    /// [`shrink_to_fit`]: String::shrink_to_fit
     /// [str]: prim@str "str"
     ///
     /// # Examples
@@ -1967,10 +1971,10 @@ impl String {
     /// this function is ideally used for data that lives for the remainder of the program's life,
     /// as dropping the returned reference will cause a memory leak.
     ///
-    /// It does not reallocate or shrink the `String`,
-    /// so the leaked allocation may include unused capacity that is not part
-    /// of the returned slice. If you don't want that, call [`into_boxed_str`],
-    /// and then [`Box::leak`].
+    /// It does not reallocate or shrink the `String`, so the leaked allocation may include unused
+    /// capacity that is not part of the returned slice. If you want to discard excess capacity,
+    /// call [`into_boxed_str`], and then [`Box::leak`] instead. However, keep in mind that
+    /// trimming the capacity may result in a reallocation and copy.
     ///
     /// [`into_boxed_str`]: Self::into_boxed_str
     ///
@@ -2155,8 +2159,8 @@ impl FromIterator<String> for String {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
-impl FromIterator<Box<str>> for String {
-    fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String {
+impl<A: Allocator> FromIterator<Box<str, A>> for String {
+    fn from_iter<I: IntoIterator<Item = Box<str, A>>>(iter: I) -> String {
         let mut buf = String::new();
         buf.extend(iter);
         buf
@@ -2237,8 +2241,8 @@ impl<'a> Extend<&'a str> for String {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
-impl Extend<Box<str>> for String {
-    fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
+impl<A: Allocator> Extend<Box<str, A>> for String {
+    fn extend<I: IntoIterator<Item = Box<str, A>>>(&mut self, iter: I) {
         iter.into_iter().for_each(move |s| self.push_str(&s));
     }
 }
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs
index 935ead2699a..86c4ea9fab0 100644
--- a/library/core/src/convert/num.rs
+++ b/library/core/src/convert/num.rs
@@ -165,8 +165,9 @@ impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0"
 impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 
 // float -> float
-// FIXME(f16_f128): adding additional `From` impls for existing types breaks inference. See
-// <https://github.com/rust-lang/rust/issues/123824>
+// FIXME(f16_f128): adding additional `From<{float}>` impls to `f32` breaks inference. See
+// <https://github.com/rust-lang/rust/issues/123831>
+impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index d1450bf12ce..d58e1dbb3e4 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1594,6 +1594,12 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn sqrtf64(x: f64) -> f64;
 
+    /// Raises an `f16` to an integer power.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::powi`](../../std/primitive.f16.html#method.powi)
+    #[rustc_nounwind]
+    pub fn powif16(a: f16, x: i32) -> f16;
     /// Raises an `f32` to an integer power.
     ///
     /// The stabilized version of this intrinsic is
@@ -1606,6 +1612,12 @@ extern "rust-intrinsic" {
     /// [`f64::powi`](../../std/primitive.f64.html#method.powi)
     #[rustc_nounwind]
     pub fn powif64(a: f64, x: i32) -> f64;
+    /// Raises an `f128` to an integer power.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::powi`](../../std/primitive.f128.html#method.powi)
+    #[rustc_nounwind]
+    pub fn powif128(a: f128, x: i32) -> f128;
 
     /// Returns the sine of an `f32`.
     ///
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 8fe81a9f528..9362dc87654 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -228,6 +228,16 @@ impl f128 {
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    ///
+    /// let f = 7.0_f128;
+    /// let g = -7.0_f128;
+    ///
+    /// assert!(f.is_sign_positive());
+    /// assert!(!g.is_sign_positive());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
@@ -241,6 +251,16 @@ impl f128 {
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    ///
+    /// let f = 7.0_f128;
+    /// let g = -7.0_f128;
+    ///
+    /// assert!(!f.is_sign_negative());
+    /// assert!(g.is_sign_negative());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 4290245ab29..c4d4584544b 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -224,6 +224,16 @@ impl f16 {
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    ///
+    /// let f = 7.0_f16;
+    /// let g = -7.0_f16;
+    ///
+    /// assert!(f.is_sign_positive());
+    /// assert!(!g.is_sign_positive());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
@@ -237,6 +247,16 @@ impl f16 {
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    ///
+    /// let f = 7.0_f16;
+    /// let g = -7.0_f16;
+    ///
+    /// assert!(!f.is_sign_negative());
+    /// assert!(g.is_sign_negative());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index d56f346d95e..db8e1f318ad 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1111,7 +1111,6 @@ impl f64 {
     /// ```
     /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
     /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
-    ///
     /// ```
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index b67930503e0..7856a1d8581 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -187,7 +187,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// This is similar to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. However, unlike `self as usize`, casting the returned address
-    /// back to a pointer yields yields a [pointer without provenance][without_provenance_mut], which is undefined
+    /// back to a pointer yields a [pointer without provenance][without_provenance_mut], which is undefined
     /// behavior to dereference. To properly restore the lost information and obtain a
     /// dereferenceable pointer, use [`with_addr`][pointer::with_addr] or
     /// [`map_addr`][pointer::map_addr].
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index b2b627fe6a9..4c6dc4bba43 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -45,25 +45,29 @@
 //! that make working with it more succinct.
 //!
 //! ```
+//! // The `is_ok` and `is_err` methods do what they say.
 //! let good_result: Result<i32, i32> = Ok(10);
 //! let bad_result: Result<i32, i32> = Err(10);
-//!
-//! // The `is_ok` and `is_err` methods do what they say.
 //! assert!(good_result.is_ok() && !good_result.is_err());
 //! assert!(bad_result.is_err() && !bad_result.is_ok());
 //!
-//! // `map` consumes the `Result` and produces another.
+//! // `map` and `map_err` consume the `Result` and produce another.
 //! let good_result: Result<i32, i32> = good_result.map(|i| i + 1);
-//! let bad_result: Result<i32, i32> = bad_result.map(|i| i - 1);
+//! let bad_result: Result<i32, i32> = bad_result.map_err(|i| i - 1);
+//! assert_eq!(good_result, Ok(11));
+//! assert_eq!(bad_result, Err(9));
 //!
 //! // Use `and_then` to continue the computation.
 //! let good_result: Result<bool, i32> = good_result.and_then(|i| Ok(i == 11));
+//! assert_eq!(good_result, Ok(true));
 //!
 //! // Use `or_else` to handle the error.
 //! let bad_result: Result<i32, i32> = bad_result.or_else(|i| Ok(i + 20));
+//! assert_eq!(bad_result, Ok(29));
 //!
 //! // Consume the result and return the contents with `unwrap`.
 //! let final_awesome_result = good_result.unwrap();
+//! assert!(final_awesome_result)
 //! ```
 //!
 //! # Results must be used
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 9bee50424b3..f82f965e67c 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -4533,21 +4533,21 @@ impl<T, const N: usize> [[T; N]] {
     /// ```
     /// #![feature(slice_flatten)]
     ///
-    /// assert_eq!([[1, 2, 3], [4, 5, 6]].flatten(), &[1, 2, 3, 4, 5, 6]);
+    /// assert_eq!([[1, 2, 3], [4, 5, 6]].as_flattened(), &[1, 2, 3, 4, 5, 6]);
     ///
     /// assert_eq!(
-    ///     [[1, 2, 3], [4, 5, 6]].flatten(),
-    ///     [[1, 2], [3, 4], [5, 6]].flatten(),
+    ///     [[1, 2, 3], [4, 5, 6]].as_flattened(),
+    ///     [[1, 2], [3, 4], [5, 6]].as_flattened(),
     /// );
     ///
     /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
-    /// assert!(slice_of_empty_arrays.flatten().is_empty());
+    /// assert!(slice_of_empty_arrays.as_flattened().is_empty());
     ///
     /// let empty_slice_of_arrays: &[[u32; 10]] = &[];
-    /// assert!(empty_slice_of_arrays.flatten().is_empty());
+    /// assert!(empty_slice_of_arrays.as_flattened().is_empty());
     /// ```
     #[unstable(feature = "slice_flatten", issue = "95629")]
-    pub const fn flatten(&self) -> &[T] {
+    pub const fn as_flattened(&self) -> &[T] {
         let len = if T::IS_ZST {
             self.len().checked_mul(N).expect("slice len overflow")
         } else {
@@ -4581,11 +4581,11 @@ impl<T, const N: usize> [[T; N]] {
     /// }
     ///
     /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
-    /// add_5_to_all(array.flatten_mut());
+    /// add_5_to_all(array.as_flattened_mut());
     /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
     /// ```
     #[unstable(feature = "slice_flatten", issue = "95629")]
-    pub fn flatten_mut(&mut self) -> &mut [T] {
+    pub fn as_flattened_mut(&mut self) -> &mut [T] {
         let len = if T::IS_ZST {
             self.len().checked_mul(N).expect("slice len overflow")
         } else {
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 72f6a3b773b..88fe29c9997 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -43,11 +43,15 @@ const DAYS_PER_WEEK: u64 = 7;
 #[rustc_layout_scalar_valid_range_end(999_999_999)]
 struct Nanoseconds(u32);
 
+impl Nanoseconds {
+    // SAFETY: 0 is within the valid range
+    const ZERO: Self = unsafe { Nanoseconds(0) };
+}
+
 impl Default for Nanoseconds {
     #[inline]
     fn default() -> Self {
-        // SAFETY: 0 is within the valid range
-        unsafe { Nanoseconds(0) }
+        Self::ZERO
     }
 }
 
@@ -236,7 +240,7 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_secs(secs: u64) -> Duration {
-        Duration::new(secs, 0)
+        Duration { secs, nanos: Nanoseconds::ZERO }
     }
 
     /// Creates a new `Duration` from the specified number of milliseconds.
@@ -256,7 +260,13 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_millis(millis: u64) -> Duration {
-        Duration::new(millis / MILLIS_PER_SEC, ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI)
+        let secs = millis / MILLIS_PER_SEC;
+        let subsec_millis = (millis % MILLIS_PER_SEC) as u32;
+        // SAFETY: (x % 1_000) * 1_000_000 < 1_000_000_000
+        //         => x % 1_000 < 1_000
+        let subsec_nanos = unsafe { Nanoseconds(subsec_millis * NANOS_PER_MILLI) };
+
+        Duration { secs, nanos: subsec_nanos }
     }
 
     /// Creates a new `Duration` from the specified number of microseconds.
@@ -276,7 +286,13 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_micros(micros: u64) -> Duration {
-        Duration::new(micros / MICROS_PER_SEC, ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO)
+        let secs = micros / MICROS_PER_SEC;
+        let subsec_micros = (micros % MICROS_PER_SEC) as u32;
+        // SAFETY: (x % 1_000_000) * 1_000 < 1_000_000_000
+        //         => x % 1_000_000 < 1_000_000
+        let subsec_nanos = unsafe { Nanoseconds(subsec_micros * NANOS_PER_MICRO) };
+
+        Duration { secs, nanos: subsec_nanos }
     }
 
     /// Creates a new `Duration` from the specified number of nanoseconds.
@@ -301,7 +317,13 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_nanos(nanos: u64) -> Duration {
-        Duration::new(nanos / (NANOS_PER_SEC as u64), (nanos % (NANOS_PER_SEC as u64)) as u32)
+        const NANOS_PER_SEC: u64 = self::NANOS_PER_SEC as u64;
+        let secs = nanos / NANOS_PER_SEC;
+        let subsec_nanos = (nanos % NANOS_PER_SEC) as u32;
+        // SAFETY: x % 1_000_000_000 < 1_000_000_000
+        let subsec_nanos = unsafe { Nanoseconds(subsec_nanos) };
+
+        Duration { secs, nanos: subsec_nanos }
     }
 
     /// Creates a new `Duration` from the specified number of weeks.
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index ffe8ffcc7f2..c91ac2fbb43 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -2609,14 +2609,14 @@ fn test_slice_from_ptr_range() {
 #[should_panic = "slice len overflow"]
 fn test_flatten_size_overflow() {
     let x = &[[(); usize::MAX]; 2][..];
-    let _ = x.flatten();
+    let _ = x.as_flattened();
 }
 
 #[test]
 #[should_panic = "slice len overflow"]
 fn test_flatten_mut_size_overflow() {
     let x = &mut [[(); usize::MAX]; 2][..];
-    let _ = x.flatten_mut();
+    let _ = x.as_flattened_mut();
 }
 
 #[test]
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index 4710d7c50b4..491235a872e 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -7,5 +7,29 @@
 #[cfg(test)]
 mod tests;
 
+#[cfg(not(test))]
+use crate::intrinsics;
+
 #[unstable(feature = "f128", issue = "116909")]
 pub use core::f128::consts;
+
+#[cfg(not(test))]
+impl f128 {
+    /// Raises a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
+    /// can even differ within the same execution from one invocation to the next.
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powi(self, n: i32) -> f128 {
+        unsafe { intrinsics::powif128(self, n) }
+    }
+}
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index c36f9f5d4c6..1cb655ffabd 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -7,5 +7,29 @@
 #[cfg(test)]
 mod tests;
 
+#[cfg(not(test))]
+use crate::intrinsics;
+
 #[unstable(feature = "f16", issue = "116909")]
 pub use core::f16::consts;
+
+#[cfg(not(test))]
+impl f16 {
+    /// Raises a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
+    /// can even differ within the same execution from one invocation to the next.
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powi(self, n: i32) -> f16 {
+        unsafe { intrinsics::powif16(self, n) }
+    }
+}
diff --git a/library/std/src/sys/pal/unix/alloc.rs b/library/std/src/sys/pal/unix/alloc.rs
index 9014bb3782a..2f908e3d0e9 100644
--- a/library/std/src/sys/pal/unix/alloc.rs
+++ b/library/std/src/sys/pal/unix/alloc.rs
@@ -59,8 +59,8 @@ unsafe impl GlobalAlloc for System {
 }
 
 cfg_if::cfg_if! {
+    // We use posix_memalign wherever possible, but not all targets have that function.
     if #[cfg(any(
-        target_os = "android",
         target_os = "redox",
         target_os = "espidf",
         target_os = "horizon",
@@ -68,23 +68,6 @@ cfg_if::cfg_if! {
     ))] {
         #[inline]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-            // On android we currently target API level 9 which unfortunately
-            // doesn't have the `posix_memalign` API used below. Instead we use
-            // `memalign`, but this unfortunately has the property on some systems
-            // where the memory returned cannot be deallocated by `free`!
-            //
-            // Upon closer inspection, however, this appears to work just fine with
-            // Android, so for this platform we should be fine to call `memalign`
-            // (which is present in API level 9). Some helpful references could
-            // possibly be chromium using memalign [1], attempts at documenting that
-            // memalign + free is ok [2] [3], or the current source of chromium
-            // which still uses memalign on android [4].
-            //
-            // [1]: https://codereview.chromium.org/10796020/
-            // [2]: https://code.google.com/p/android/issues/detail?id=35391
-            // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
-            // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
-            //                                       /memory/aligned_memory.cc
             libc::memalign(layout.align(), layout.size()) as *mut u8
         }
     } else {
diff --git a/library/stdarch b/library/stdarch
-Subproject c0257c1660e78c80ad1b9136fcc5555b14da5b4
+Subproject df3618d9f35165f4bc548114e511c49c29e1fd9
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 48a6602e2df..66692a2a2cb 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1136,6 +1136,11 @@ pub fn rustc_cargo_env(
         cargo.env("CFG_DEFAULT_LINKER", s);
     }
 
+    // Enable rustc's env var for `rust-lld` when requested.
+    if builder.config.lld_enabled {
+        cargo.env("CFG_USE_SELF_CONTAINED_LINKER", "1");
+    }
+
     if builder.config.rust_verify_llvm_ir {
         cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
     }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index bb51433a3dc..19119a073c5 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1307,6 +1307,9 @@ impl Config {
             toml_path = config.src.join(toml_path);
         }
 
+        let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel")));
+        let ci_channel = file_content.trim_end();
+
         // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
         // but not if `config.toml` hasn't been created.
         let mut toml = if !using_default_path || toml_path.exists() {
@@ -1532,7 +1535,9 @@ impl Config {
         let mut debuginfo_level_tests = None;
         let mut optimize = None;
         let mut omit_git_hash = None;
+        let mut lld_enabled = None;
 
+        let mut is_user_configured_rust_channel = false;
         if let Some(rust) = toml.rust {
             let Rust {
                 optimize: optimize_toml,
@@ -1565,7 +1570,7 @@ impl Config {
                 dist_src,
                 save_toolstates,
                 codegen_backends,
-                lld,
+                lld: lld_enabled_toml,
                 llvm_tools,
                 llvm_bitcode_linker,
                 deny_warnings,
@@ -1590,6 +1595,7 @@ impl Config {
                 lld_mode,
             } = rust;
 
+            is_user_configured_rust_channel = channel.is_some();
             set(&mut config.channel, channel);
 
             config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc);
@@ -1597,8 +1603,6 @@ impl Config {
             if config.download_rustc_commit.is_some() {
                 // We need the channel used by the downloaded compiler to match the one we set for rustdoc;
                 // otherwise rustdoc-ui tests break.
-                let ci_channel = t!(fs::read_to_string(config.src.join("src/ci/channel")));
-                let ci_channel = ci_channel.trim_end();
                 if config.channel != ci_channel
                     && !(config.channel == "dev" && ci_channel == "nightly")
                 {
@@ -1620,6 +1624,7 @@ impl Config {
             debuginfo_level_std = debuginfo_level_std_toml;
             debuginfo_level_tools = debuginfo_level_tools_toml;
             debuginfo_level_tests = debuginfo_level_tests_toml;
+            lld_enabled = lld_enabled_toml;
 
             config.rust_split_debuginfo_for_build_triple = split_debuginfo
                 .as_deref()
@@ -1653,18 +1658,8 @@ impl Config {
                 config.incremental = true;
             }
             set(&mut config.lld_mode, lld_mode);
-            set(&mut config.lld_enabled, lld);
             set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
 
-            if matches!(config.lld_mode, LldMode::SelfContained)
-                && !config.lld_enabled
-                && flags.stage.unwrap_or(0) > 0
-            {
-                panic!(
-                    "Trying to use self-contained lld as a linker, but LLD is not being added to the sysroot. Enable it with rust.lld = true."
-                );
-            }
-
             config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
             config.rustc_parallel =
                 parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly");
@@ -1725,6 +1720,10 @@ impl Config {
         config.omit_git_hash = omit_git_hash.unwrap_or(default);
         config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
 
+        if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel {
+            ci_channel.clone_into(&mut config.channel);
+        }
+
         if let Some(llvm) = toml.llvm {
             let Llvm {
                 optimize: optimize_toml,
@@ -1954,6 +1953,43 @@ impl Config {
         config.llvm_plugins = llvm_plugins.unwrap_or(false);
         config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
 
+        // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
+        // build our internal lld and use it as the default linker, by setting the `rust.lld` config
+        // to true by default:
+        // - on the `x86_64-unknown-linux-gnu` target
+        // - on the `dev` and `nightly` channels
+        // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
+        //   we're also able to build the corresponding lld
+        // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
+        //   lld
+        // - otherwise, we'd be using an external llvm, and lld would not necessarily available and
+        //   thus, disabled
+        // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
+        //   when the config sets `rust.lld = false`
+        if config.build.triple == "x86_64-unknown-linux-gnu"
+            && config.hosts == [config.build]
+            && (config.channel == "dev" || config.channel == "nightly")
+        {
+            let no_llvm_config = config
+                .target_config
+                .get(&config.build)
+                .is_some_and(|target_config| target_config.llvm_config.is_none());
+            let enable_lld = config.llvm_from_ci || no_llvm_config;
+            // Prefer the config setting in case an explicit opt-out is needed.
+            config.lld_enabled = lld_enabled.unwrap_or(enable_lld);
+        } else {
+            set(&mut config.lld_enabled, lld_enabled);
+        }
+
+        if matches!(config.lld_mode, LldMode::SelfContained)
+            && !config.lld_enabled
+            && flags.stage.unwrap_or(0) > 0
+        {
+            panic!(
+                "Trying to use self-contained lld as a linker, but LLD is not being added to the sysroot. Enable it with rust.lld = true."
+            );
+        }
+
         let default = debug == Some(true);
         config.rust_debug_assertions = debug_assertions.unwrap_or(default);
         config.rust_debug_assertions_std =
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index a1c9ddebb5d..2f9eaf51c34 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -185,4 +185,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: r#"The compiler profile now defaults to rust.debuginfo-level = "line-tables-only""#,
     },
+    ChangeInfo {
+        change_id: 124129,
+        severity: ChangeSeverity::Warning,
+        summary: "`rust.lld` has a new default value of `true` on `x86_64-unknown-linux-gnu`. Starting at stage1, `rust-lld` will thus be this target's default linker. No config changes should be necessary.",
+    },
 ];
diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md
index ff80f140482..ab95aa2e5a1 100644
--- a/src/doc/rustc/src/linker-plugin-lto.md
+++ b/src/doc/rustc/src/linker-plugin-lto.md
@@ -200,6 +200,7 @@ The following table shows known good combinations of toolchain versions.
 | 1.60 - 1.64  |      14       |
 | 1.65 - 1.69  |      15       |
 | 1.70 - 1.72  |      16       |
-| 1.73 - 1.74  |      17       |
+| 1.73 - 1.77  |      17       |
+| 1.78         |      18       |
 
 Note that the compatibility policy for this feature might change in the future.
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index 69fb7e3313f..3e104bdb470 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -417,6 +417,12 @@ When `rustdoc` receives this flag, it will print an extra "Version (version)" in
 the crate root's docs. You can use this flag to differentiate between different versions of your
 library's documentation.
 
+## `-`: load source code from the standard input
+
+If you specify `-` as the INPUT on the command line, then `rustdoc` will read the
+source code from stdin (standard input stream) until the EOF, instead of the file
+system with an otherwise specified path.
+
 ## `@path`: load command-line flags from a path
 
 If you specify `@path` on the command-line, then it will open `path` and read
diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py
index db3afb00369..abbd802dcdd 100644
--- a/src/etc/lldb_lookup.py
+++ b/src/etc/lldb_lookup.py
@@ -92,7 +92,7 @@ def synthetic_lookup(valobj, dict):
         return StdVecSyntheticProvider(valobj, dict)
     if rust_type == RustType.STD_VEC_DEQUE:
         return StdVecDequeSyntheticProvider(valobj, dict)
-    if rust_type == RustType.STD_SLICE:
+    if rust_type == RustType.STD_SLICE or rust_type == RustType.STD_STR:
         return StdSliceSyntheticProvider(valobj, dict)
 
     if rust_type == RustType.STD_HASH_MAP:
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index a87fd6078b8..c6330117380 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -159,6 +159,9 @@ def StdStrSummaryProvider(valobj, dict):
     # logger = Logger.Logger()
     # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName())
 
+    # the code below assumes non-synthetic value, this makes sure the assumption holds
+    valobj = valobj.GetNonSyntheticValue()
+
     length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
     if length == 0:
         return '""'
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index c464820413c..bccad29e0a9 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -119,7 +119,7 @@ fn synthesize_auto_trait_impl<'tcx>(
         attrs: Default::default(),
         item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
         kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
-            unsafety: hir::Unsafety::Normal,
+            safety: hir::Safety::Safe,
             generics,
             trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref, ThinVec::new())),
             for_: clean_middle_ty(ty::Binder::dummy(ty), cx, None, None),
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 8ed6ee014f3..29be3a70d54 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
 use rustc_infer::traits;
-use rustc_middle::ty::{self, ToPredicate};
+use rustc_middle::ty::{self, Upcast};
 use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -64,7 +64,7 @@ pub(crate) fn synthesize_blanket_impls(
                 .instantiate(tcx, impl_args)
                 .predicates
                 .into_iter()
-                .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(tcx)));
+                .chain(Some(impl_trait_ref.upcast(tcx)));
             for predicate in predicates {
                 let obligation = traits::Obligation::new(
                     tcx,
@@ -87,7 +87,7 @@ pub(crate) fn synthesize_blanket_impls(
                 attrs: Default::default(),
                 item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                 kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
-                    unsafety: hir::Unsafety::Normal,
+                    safety: hir::Safety::Safe,
                     generics: clean_ty_generics(
                         cx,
                         tcx.generics_of(impl_def_id),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 7d8b6f34cbb..2919a4c4beb 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -613,7 +613,7 @@ pub(crate) fn build_impl(
         did,
         None,
         clean::ImplItem(Box::new(clean::Impl {
-            unsafety: hir::Unsafety::Normal,
+            safety: hir::Safety::Safe,
             generics,
             trait_,
             for_,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0ab23d159a6..73737da482d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2077,7 +2077,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             let generic_params = clean_bound_vars(sig.bound_vars());
 
             BareFunction(Box::new(BareFunctionDecl {
-                unsafety: sig.unsafety(),
+                safety: sig.safety(),
                 generic_params,
                 decl,
                 abi: sig.abi(),
@@ -2565,7 +2565,7 @@ fn clean_bare_fn_ty<'tcx>(
         let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
         (generic_params, decl)
     });
-    BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
+    BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params }
 }
 
 pub(crate) fn reexport_chain<'tcx>(
@@ -2874,7 +2874,7 @@ fn clean_impl<'tcx>(
         });
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
         let kind = ImplItem(Box::new(Impl {
-            unsafety: impl_.unsafety,
+            safety: impl_.safety,
             generics: clean_generics(impl_.generics, cx),
             trait_,
             for_,
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index af81cc6878e..b54ec624524 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -636,17 +636,17 @@ impl Item {
                 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
                 ty::Asyncness::No => hir::IsAsync::NotAsync,
             };
-            hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }
+            hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness }
         }
         let header = match *self.kind {
             ItemKind::ForeignFunctionItem(_) => {
                 let def_id = self.def_id().unwrap();
                 let abi = tcx.fn_sig(def_id).skip_binder().abi();
                 hir::FnHeader {
-                    unsafety: if abi == Abi::RustIntrinsic {
+                    safety: if abi == Abi::RustIntrinsic {
                         intrinsic_operation_unsafety(tcx, def_id.expect_local())
                     } else {
-                        hir::Unsafety::Unsafe
+                        hir::Safety::Unsafe
                     },
                     abi,
                     constness: if abi == Abi::RustIntrinsic
@@ -1448,8 +1448,8 @@ impl Trait {
     pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
         tcx.is_doc_notable_trait(self.def_id)
     }
-    pub(crate) fn unsafety(&self, tcx: TyCtxt<'_>) -> hir::Unsafety {
-        tcx.trait_def(self.def_id).unsafety
+    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
+        tcx.trait_def(self.def_id).safety
     }
     pub(crate) fn is_object_safe(&self, tcx: TyCtxt<'_>) -> bool {
         tcx.check_is_object_safe(self.def_id)
@@ -2344,7 +2344,7 @@ pub(crate) struct OpaqueTy {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct BareFunctionDecl {
-    pub(crate) unsafety: hir::Unsafety,
+    pub(crate) safety: hir::Safety,
     pub(crate) generic_params: Vec<GenericParamDef>,
     pub(crate) decl: FnDecl,
     pub(crate) abi: Abi,
@@ -2446,7 +2446,7 @@ impl ConstantKind {
 
 #[derive(Clone, Debug)]
 pub(crate) struct Impl {
-    pub(crate) unsafety: hir::Unsafety,
+    pub(crate) safety: hir::Safety,
     pub(crate) generics: Generics,
     pub(crate) trait_: Option<Path>,
     pub(crate) for_: Type,
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index d4468fecba4..012afada1e5 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -1,6 +1,9 @@
 use std::collections::BTreeMap;
 use std::ffi::OsStr;
 use std::fmt;
+use std::io;
+use std::io::Read;
+use std::path::Path;
 use std::path::PathBuf;
 use std::str::FromStr;
 
@@ -9,14 +12,14 @@ use rustc_session::config::{
     self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
 };
 use rustc_session::config::{get_cmd_lint_options, nightly_options};
-use rustc_session::config::{
-    CodegenOptions, ErrorOutputType, Externs, JsonUnusedExterns, UnstableOptions,
-};
+use rustc_session::config::{CodegenOptions, ErrorOutputType, Externs, Input};
+use rustc_session::config::{JsonUnusedExterns, UnstableOptions};
 use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::EarlyDiagCtxt;
 use rustc_span::edition::Edition;
+use rustc_span::FileName;
 use rustc_target::spec::TargetTriple;
 
 use crate::core::new_dcx;
@@ -60,7 +63,7 @@ impl TryFrom<&str> for OutputFormat {
 pub(crate) struct Options {
     // Basic options / Options passed directly to rustc
     /// The crate root or Markdown file to load.
-    pub(crate) input: PathBuf,
+    pub(crate) input: Input,
     /// The name of the crate being documented.
     pub(crate) crate_name: Option<String>,
     /// Whether or not this is a bin crate
@@ -179,7 +182,7 @@ impl fmt::Debug for Options {
         }
 
         f.debug_struct("Options")
-            .field("input", &self.input)
+            .field("input", &self.input.source_name())
             .field("crate_name", &self.crate_name)
             .field("bin_crate", &self.bin_crate)
             .field("proc_macro_crate", &self.proc_macro_crate)
@@ -320,6 +323,23 @@ impl RenderOptions {
     }
 }
 
+/// Create the input (string or file path)
+///
+/// Warning: Return an unrecoverable error in case of error!
+fn make_input(early_dcx: &EarlyDiagCtxt, input: &str) -> Input {
+    if input == "-" {
+        let mut src = String::new();
+        if io::stdin().read_to_string(&mut src).is_err() {
+            // Immediately stop compilation if there was an issue reading
+            // the input (for example if the input stream is not UTF-8).
+            early_dcx.early_fatal("couldn't read from stdin, as it did not contain valid UTF-8");
+        }
+        Input::Str { name: FileName::anon_source_code(&src), input: src }
+    } else {
+        Input::File(PathBuf::from(input))
+    }
+}
+
 impl Options {
     /// Parses the given command-line for options. If an error message or other early-return has
     /// been printed, returns `Err` with the exit code.
@@ -447,15 +467,16 @@ impl Options {
 
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
 
-        let input = PathBuf::from(if describe_lints {
+        let input = if describe_lints {
             "" // dummy, this won't be used
-        } else if matches.free.is_empty() {
-            dcx.fatal("missing file operand");
-        } else if matches.free.len() > 1 {
-            dcx.fatal("too many file operands");
         } else {
-            &matches.free[0]
-        });
+            match matches.free.as_slice() {
+                [] => dcx.fatal("missing file operand"),
+                [input] => input,
+                _ => dcx.fatal("too many file operands"),
+            }
+        };
+        let input = make_input(early_dcx, &input);
 
         let externs = parse_externs(early_dcx, matches, &unstable_opts);
         let extern_html_root_urls = match parse_extern_html_roots(matches) {
@@ -792,8 +813,10 @@ impl Options {
     }
 
     /// Returns `true` if the file given as `self.input` is a Markdown file.
-    pub(crate) fn markdown_input(&self) -> bool {
-        self.input.extension().is_some_and(|e| e == "md" || e == "markdown")
+    pub(crate) fn markdown_input(&self) -> Option<&Path> {
+        self.input
+            .opt_path()
+            .filter(|p| matches!(p.extension(), Some(e) if e == "md" || e == "markdown"))
     }
 }
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 25b78d9598d..feb03b9a823 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -32,7 +32,7 @@ use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
 use crate::formats::cache::Cache;
 use crate::passes::{self, Condition::*};
 
-pub(crate) use rustc_session::config::{Input, Options, UnstableOptions};
+pub(crate) use rustc_session::config::{Options, UnstableOptions};
 
 pub(crate) struct DocContext<'tcx> {
     pub(crate) tcx: TyCtxt<'tcx>,
@@ -204,8 +204,6 @@ pub(crate) fn create_config(
     // Add the doc cfg into the doc build.
     cfgs.push("doc".to_string());
 
-    let input = Input::File(input);
-
     // By default, rustdoc ignores all lints.
     // Specifically unblock lints relevant to documentation or the lint machinery itself.
     let mut lints_to_show = vec![
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 19aa5ef949e..82f9cf1feae 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -93,8 +93,6 @@ pub(crate) fn run(
     dcx: &rustc_errors::DiagCtxt,
     options: RustdocOptions,
 ) -> Result<(), ErrorGuaranteed> {
-    let input = config::Input::File(options.input.clone());
-
     let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
 
     // See core::create_config for what's going on here.
@@ -140,7 +138,7 @@ pub(crate) fn run(
         opts: sessopts,
         crate_cfg: cfgs,
         crate_check_cfg: options.check_cfgs.clone(),
-        input,
+        input: options.input.clone(),
         output_file: None,
         output_dir: None,
         file_loader: None,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 241dc37ab9c..587c464b0ed 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1013,7 +1013,7 @@ fn fmt_type<'cx>(
         }
         clean::BareFunction(ref decl) => {
             print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?;
-            decl.unsafety.print_with_space().fmt(f)?;
+            decl.safety.print_with_space().fmt(f)?;
             print_abi_with_space(decl.abi).fmt(f)?;
             if f.alternate() {
                 f.write_str("fn")?;
@@ -1303,7 +1303,7 @@ impl clean::Impl {
                 // Link should match `# Trait implementations`
 
                 print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
-                bare_fn.unsafety.print_with_space().fmt(f)?;
+                bare_fn.safety.print_with_space().fmt(f)?;
                 print_abi_with_space(bare_fn.abi).fmt(f)?;
                 let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };
                 primitive_link_fragment(
@@ -1604,11 +1604,11 @@ pub(crate) trait PrintWithSpace {
     fn print_with_space(&self) -> &str;
 }
 
-impl PrintWithSpace for hir::Unsafety {
+impl PrintWithSpace for hir::Safety {
     fn print_with_space(&self) -> &str {
         match self {
-            hir::Unsafety::Unsafe => "unsafe ",
-            hir::Unsafety::Normal => "",
+            hir::Safety::Unsafe => "unsafe ",
+            hir::Safety::Safe => "",
         }
     }
 }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 18323e0b8ad..f3ae4b76883 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -934,7 +934,7 @@ fn assoc_method(
         RenderMode::ForDeref { .. } => "",
     };
     let asyncness = header.asyncness.print_with_space();
-    let unsafety = header.unsafety.print_with_space();
+    let safety = header.safety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let href = assoc_href_attr(meth, link, cx);
 
@@ -945,7 +945,7 @@ fn assoc_method(
         + defaultness.len()
         + constness.len()
         + asyncness.len()
-        + unsafety.len()
+        + safety.len()
         + abi.len()
         + name.as_str().len()
         + generics_len;
@@ -964,14 +964,14 @@ fn assoc_method(
     w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
     write!(
         w,
-        "{indent}{vis}{defaultness}{constness}{asyncness}{unsafety}{abi}fn \
+        "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
          <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
         indent = indent_str,
         vis = vis,
         defaultness = defaultness,
         constness = constness,
         asyncness = asyncness,
-        unsafety = unsafety,
+        safety = safety,
         abi = abi,
         href = href,
         name = name,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 7de2aea1c04..c7a23aa8503 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -492,7 +492,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
 
                 let unsafety_flag = match *myitem.kind {
                     clean::FunctionItem(_) | clean::ForeignFunctionItem(_)
-                        if myitem.fn_header(tcx).unwrap().unsafety == hir::Unsafety::Unsafe =>
+                        if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe =>
                     {
                         "<sup title=\"unsafe function\">âš </sup>"
                     }
@@ -616,7 +616,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
     let tcx = cx.tcx();
     let header = it.fn_header(tcx).expect("printing a function which isn't a function");
     let constness = print_constness_with_space(&header.constness, it.const_stability(tcx));
-    let unsafety = header.unsafety.print_with_space();
+    let safety = header.safety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let asyncness = header.asyncness.print_with_space();
     let visibility = visibility_print_with_space(it, cx).to_string();
@@ -627,7 +627,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
         + visibility.len()
         + constness.len()
         + asyncness.len()
-        + unsafety.len()
+        + safety.len()
         + abi.len()
         + name.as_str().len()
         + generics_len;
@@ -638,13 +638,13 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
         w.reserve(header_len);
         write!(
             w,
-            "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
+            "{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
                 {name}{generics}{decl}{notable_traits}{where_clause}",
             attrs = render_attributes_in_pre(it, "", cx),
             vis = visibility,
             constness = constness,
             asyncness = asyncness,
-            unsafety = unsafety,
+            safety = safety,
             abi = abi,
             name = name,
             generics = f.generics.print(cx),
@@ -674,10 +674,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
     wrap_item(w, |mut w| {
         write!(
             w,
-            "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}",
+            "{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
             attrs = render_attributes_in_pre(it, "", cx),
             vis = visibility_print_with_space(it, cx),
-            unsafety = t.unsafety(tcx).print_with_space(),
+            safety = t.safety(tcx).print_with_space(),
             is_auto = if t.is_auto(tcx) { "auto " } else { "" },
             name = it.name.unwrap(),
             generics = t.generics.print(cx),
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 35b99ab46f0..f856b4e9f16 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -619,10 +619,10 @@ impl FromWithTcx<clean::Term> for Term {
 
 impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
     fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
-        let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
+        let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
         FunctionPointer {
             header: Header {
-                unsafe_: matches!(unsafety, rustc_hir::Unsafety::Unsafe),
+                unsafe_: matches!(safety, rustc_hir::Safety::Unsafe),
                 const_: false,
                 async_: false,
                 abi: convert_abi(abi),
@@ -651,7 +651,7 @@ impl FromWithTcx<clean::FnDecl> for FnDecl {
 impl FromWithTcx<clean::Trait> for Trait {
     fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
         let is_auto = trait_.is_auto(tcx);
-        let is_unsafe = trait_.unsafety(tcx) == rustc_hir::Unsafety::Unsafe;
+        let is_unsafe = trait_.safety(tcx) == rustc_hir::Safety::Unsafe;
         let is_object_safe = trait_.is_object_safe(tcx);
         let clean::Trait { items, generics, bounds, .. } = trait_;
         Trait {
@@ -678,7 +678,7 @@ impl FromWithTcx<clean::PolyTrait> for PolyTrait {
 impl FromWithTcx<clean::Impl> for Impl {
     fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
         let provided_trait_methods = impl_.provided_trait_methods(tcx);
-        let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
+        let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
         // FIXME: use something like ImplKind in JSON?
         let (synthetic, blanket_impl) = match kind {
             clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),
@@ -690,7 +690,7 @@ impl FromWithTcx<clean::Impl> for Impl {
             ty::ImplPolarity::Negative => true,
         };
         Impl {
-            is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
+            is_unsafe: safety == rustc_hir::Safety::Unsafe,
             generics: generics.into_tcx(tcx),
             provided_trait_methods: provided_trait_methods
                 .into_iter()
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index f2a7518b4ce..0650afb90c7 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -730,10 +730,10 @@ fn main_args(
         core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
 
     match (options.should_test, options.markdown_input()) {
-        (true, true) => return wrap_return(&diag, markdown::test(options)),
-        (true, false) => return doctest::run(&diag, options),
-        (false, true) => {
-            let input = options.input.clone();
+        (true, Some(_)) => return wrap_return(&diag, markdown::test(options)),
+        (true, None) => return doctest::run(&diag, options),
+        (false, Some(input)) => {
+            let input = input.to_owned();
             let edition = options.edition;
             let config = core::create_config(options, &render_options, using_internal_features);
 
@@ -747,7 +747,7 @@ fn main_args(
                 }),
             );
         }
-        (false, false) => {}
+        (false, None) => {}
     }
 
     // need to move these items separately because we lose them by the time the closure is called,
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index dcd2cf02a30..7289ed56dc7 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -144,8 +144,14 @@ pub(crate) fn render<P: AsRef<Path>>(
 
 /// Runs any tests/code examples in the markdown file `input`.
 pub(crate) fn test(options: Options) -> Result<(), String> {
-    let input_str = read_to_string(&options.input)
-        .map_err(|err| format!("{input}: {err}", input = options.input.display()))?;
+    use rustc_session::config::Input;
+    let input_str = match &options.input {
+        Input::File(path) => {
+            read_to_string(&path).map_err(|err| format!("{}: {err}", path.display()))?
+        }
+        Input::Str { name: _, input } => input.clone(),
+    };
+
     let mut opts = GlobalTestOptions::default();
     opts.no_crate_inject = true;
 
@@ -155,12 +161,12 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
     generate_args_file(&file_path, &options)?;
 
     let mut collector = Collector::new(
-        options.input.display().to_string(),
+        options.input.filestem().to_string(),
         options.clone(),
         true,
         opts,
         None,
-        Some(options.input),
+        options.input.opt_path().map(ToOwned::to_owned),
         options.enable_per_target_ignores,
         file_path,
     );
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index e788069ea80..1c5a6dcfb1f 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -188,7 +188,19 @@ pub enum TypeBindingKind {
     Constraint(Vec<GenericBound>),
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+/// An opaque identifier for an item.
+///
+/// It can be used to lookup in [Crate::index] or [Crate::paths] to resolve it
+/// to an [Item].
+///
+/// Id's are only valid within a single JSON blob. They cannot be used to
+/// resolve references between the JSON output's for different crates.
+///
+/// Rustdoc makes no guarantees about the inner value of Id's. Applications
+/// should treat them as opaque keys to lookup items, and avoid attempting
+/// to parse them, or otherwise depend on any implementation details.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+// FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types.
 pub struct Id(pub String);
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 4de0094ac78743d2c8ff682489e35c8a7cafe8e
+Subproject 0de7f2ec6c39d68022e6b97a39559d2f4dbf393
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 9662c8f4fe2..2a644922fb1 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -5,13 +5,13 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
-    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource, Unsafety,
+    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Safety, Impl, Item, ItemKind, UnsafeSource,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt,
+    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, Upcast, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
@@ -415,7 +415,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
         }
 
         if let Some(header) = kind.header()
-            && header.unsafety == Unsafety::Unsafe
+            && header.safety == Safety::Unsafe
         {
             self.has_unsafe = true;
         }
@@ -503,7 +503,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
                     trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
                     polarity: ty::PredicatePolarity::Positive,
                 })
-                .to_predicate(tcx)
+                .upcast(tcx)
             }),
         )),
         Reveal::UserFacing,
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index f935ae2e3e4..36ba19698c7 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{is_doc_hidden, return_ty};
-use rustc_hir::{BodyId, FnSig, OwnerId, Unsafety};
+use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::{sym, Span};
@@ -33,14 +33,14 @@ pub fn check(
     }
 
     let span = cx.tcx.def_span(owner_id);
-    match (headers.safety, sig.header.unsafety) {
-        (false, Unsafety::Unsafe) => span_lint(
+    match (headers.safety, sig.header.safety) {
+        (false, Safety::Unsafe) => span_lint(
             cx,
             MISSING_SAFETY_DOC,
             span,
             "unsafe function's docs miss `# Safety` section",
         ),
-        (true, Unsafety::Normal) => span_lint(
+        (true, Safety::Safe) => span_lint(
             cx,
             UNNECESSARY_SAFETY_DOC,
             span,
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 4bced104d3b..7fdb582e640 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -12,7 +12,7 @@ use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
 use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, TraitItemKind, Unsafety};
+use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
@@ -415,13 +415,13 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
                     }
                 },
                 ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
-                    (false, Unsafety::Unsafe) => span_lint(
+                    (false, Safety::Unsafe) => span_lint(
                         cx,
                         MISSING_SAFETY_DOC,
                         cx.tcx.def_span(item.owner_id),
                         "docs for unsafe trait missing `# Safety` section",
                     ),
-                    (true, Unsafety::Normal) => span_lint(
+                    (true, Safety::Safe) => span_lint(
                         cx,
                         UNNECESSARY_SAFETY_DOC,
                         cx.tcx.def_span(item.owner_id),
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 306a4a9e55c..b58018ca035 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -5,7 +5,7 @@ use clippy_utils::ty::type_diagnostic_name;
 use clippy_utils::usage::{local_used_after_expr, local_used_in};
 use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id};
 use rustc_errors::Applicability;
-use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
+use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Safety, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
@@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                     ty::FnPtr(sig) => sig.skip_binder(),
                     ty::Closure(_, subs) => cx
                         .tcx
-                        .signature_unclosure(subs.as_closure().sig(), Unsafety::Normal)
+                        .signature_unclosure(subs.as_closure().sig(), Safety::Safe)
                         .skip_binder(),
                     _ => {
                         if typeck.type_dependent_def_id(body.value.hir_id).is_some()
@@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                             && let output = typeck.expr_ty(body.value)
                             && let ty::Tuple(tys) = *subs.type_at(1).kind()
                         {
-                            cx.tcx.mk_fn_sig(tys, output, false, Unsafety::Normal, Abi::Rust)
+                            cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
                         } else {
                             return;
                         }
@@ -241,11 +241,9 @@ fn check_inputs(
 }
 
 fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool {
-    call_sig.unsafety == Unsafety::Normal
+    call_sig.safety == Safety::Safe
         && !has_late_bound_to_non_late_bound_regions(
-            cx.tcx
-                .signature_unclosure(closure.sig(), Unsafety::Normal)
-                .skip_binder(),
+            cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder(),
             call_sig,
         )
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index 8ac17e17688..7729c556e1f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
+use rustc_hir::{Body, ExprKind, FnDecl, Safety, ImplicitSelfKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Span;
@@ -34,7 +34,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
         ImplicitSelfKind::None => return,
     };
 
-    let name = if sig.header.unsafety == Unsafety::Unsafe {
+    let name = if sig.header.safety == Safety::Unsafe {
         name.strip_suffix("_unchecked").unwrap_or(name)
     } else {
         name
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 995dd782cbb..b44a5f20ef6 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -19,30 +19,30 @@ pub(super) fn check_fn<'tcx>(
     body: &'tcx hir::Body<'tcx>,
     def_id: LocalDefId,
 ) {
-    let unsafety = match kind {
-        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety,
-        intravisit::FnKind::Method(_, sig) => sig.header.unsafety,
+    let safety = match kind {
+        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { safety, .. }) => safety,
+        intravisit::FnKind::Method(_, sig) => sig.header.safety,
         intravisit::FnKind::Closure => return,
     };
 
-    check_raw_ptr(cx, unsafety, decl, body, def_id);
+    check_raw_ptr(cx, safety, decl, body, def_id);
 }
 
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
-        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.owner_id.def_id);
+        check_raw_ptr(cx, sig.header.safety, sig.decl, body, item.owner_id.def_id);
     }
 }
 
 fn check_raw_ptr<'tcx>(
     cx: &LateContext<'tcx>,
-    unsafety: hir::Unsafety,
+    safety: hir::Safety,
     decl: &'tcx hir::FnDecl<'tcx>,
     body: &'tcx hir::Body<'tcx>,
     def_id: LocalDefId,
 ) {
-    if unsafety == hir::Unsafety::Normal && cx.effective_visibilities.is_exported(def_id) {
+    if safety == hir::Safety::Safe && cx.effective_visibilities.is_exported(def_id) {
         let raw_ptrs = iter_input_pats(decl, body)
             .filter_map(|arg| raw_ptr_arg(cx, arg))
             .collect::<HirIdSet>();
@@ -58,7 +58,7 @@ fn check_raw_ptr<'tcx>(
                     },
                     hir::ExprKind::MethodCall(_, recv, args, _) => {
                         let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap();
-                        if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().unsafety == hir::Unsafety::Unsafe {
+                        if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().safety == hir::Safety::Unsafe {
                             check_arg(cx, &raw_ptrs, recv);
                             for arg in args {
                                 check_arg(cx, &raw_ptrs, arg);
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 157f6105984..9aedf5ec7e8 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
 use clippy_utils::{return_ty, trait_ref_of_method};
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Safety};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
         if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // #11201
             && let header = signature.header
-            && header.unsafety == Unsafety::Normal
+            && header.safety == Safety::Safe
             && header.abi == Abi::Rust
             && impl_item.ident.name == sym::to_string
             && let decl = signature.decl
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 63545d6c503..2b92bff016d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -5038,7 +5038,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr
 }
 
 const FN_HEADER: hir::FnHeader = hir::FnHeader {
-    unsafety: hir::Unsafety::Normal,
+    safety: hir::Safety::Safe,
     constness: hir::Constness::NotConst,
     asyncness: hir::IsAsync::NotAsync,
     abi: rustc_target::spec::abi::Abi::Rust,
@@ -5214,7 +5214,5 @@ impl OutType {
 }
 
 fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
-    expected.constness == actual.constness
-        && expected.unsafety == actual.unsafety
-        && expected.asyncness == actual.asyncness
+    expected.constness == actual.constness && expected.safety == actual.safety && expected.asyncness == actual.asyncness
 }
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 0e138066780..5306205aed7 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable};
 use core::ops::ControlFlow::Continue;
 use hir::def::{DefKind, Res};
-use hir::{BlockCheckMode, ExprKind, QPath, UnOp, Unsafety};
+use hir::{BlockCheckMode, ExprKind, Safety, QPath, UnOp};
 use rustc_ast::Mutability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -133,7 +133,7 @@ fn collect_unsafe_exprs<'tcx>(
                     ty::FnPtr(sig) => sig,
                     _ => return Continue(Descend::Yes),
                 };
-                if sig.unsafety() == Unsafety::Unsafe {
+                if sig.safety() == Safety::Unsafe {
                     unsafe_ops.push(("unsafe function call occurs here", expr.span));
                 }
             },
@@ -144,7 +144,7 @@ fn collect_unsafe_exprs<'tcx>(
                     .type_dependent_def_id(expr.hir_id)
                     .map(|def_id| cx.tcx.fn_sig(def_id))
                 {
-                    if sig.skip_binder().unsafety() == Unsafety::Unsafe {
+                    if sig.skip_binder().safety() == Safety::Unsafe {
                         unsafe_ops.push(("unsafe method call occurs here", expr.span));
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 78dd1e05162..b60fea3f03e 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                     if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
                         let name = impl_item.ident.name;
                         let id = impl_item.owner_id;
-                        if sig.header.unsafety == hir::Unsafety::Unsafe {
+                        if sig.header.safety == hir::Safety::Unsafe {
                             // can't be implemented for unsafe new
                             return;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 2534e3c8468..65929cd5fea 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -12,7 +12,7 @@ use rustc_hir::hir_id::{HirId, HirIdMap};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{
     self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind,
-    ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, Unsafety,
+    ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, Safety, TraitFn, TraitItem, TraitItemKind, TyKind,
 };
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{Obligation, ObligationCause};
@@ -542,7 +542,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
         if let Some(args) = args
             && !args.is_empty()
             && body.map_or(true, |body| {
-                sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, body.value)
+                sig.header.safety == Safety::Unsafe || contains_unsafe_block(cx, body.value)
             })
         {
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index cbd16180077..4120bb1331b 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -200,7 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
         let item_has_safety_comment = item_has_safety_comment(cx, item);
         match (&item.kind, item_has_safety_comment) {
             // lint unsafe impl without safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => {
+            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety == hir::Safety::Unsafe => {
                 if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
                     && !is_unsafe_from_proc_macro(cx, item.span)
                 {
@@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 }
             },
             // lint safe impl with unnecessary safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => {
+            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety == hir::Safety::Safe => {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index d3bbc66bcae..d4a5f547211 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -386,21 +386,21 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
         (
             Trait(box ast::Trait {
                 is_auto: la,
-                unsafety: lu,
+                safety: lu,
                 generics: lg,
                 bounds: lb,
                 items: li,
             }),
             Trait(box ast::Trait {
                 is_auto: ra,
-                unsafety: ru,
+                safety: ru,
                 generics: rg,
                 bounds: rb,
                 items: ri,
             }),
         ) => {
             la == ra
-                && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
+                && matches!(lu, Safety::Default) == matches!(ru, Safety::Default)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
                 && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
@@ -408,7 +408,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
         (TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, eq_generic_bound),
         (
             Impl(box ast::Impl {
-                unsafety: lu,
+                safety: lu,
                 polarity: lp,
                 defaultness: ld,
                 constness: lc,
@@ -418,7 +418,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 items: li,
             }),
             Impl(box ast::Impl {
-                unsafety: ru,
+                safety: ru,
                 polarity: rp,
                 defaultness: rd,
                 constness: rc,
@@ -428,7 +428,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 items: ri,
             }),
         ) => {
-            matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
+            matches!(lu, Safety::Default) == matches!(ru, Safety::Default)
                 && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive)
                 && eq_defaultness(*ld, *rd)
                 && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
@@ -605,7 +605,7 @@ fn eq_opt_coroutine_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) ->
 }
 
 pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
-    matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
+    matches!(l.safety, Safety::Default) == matches!(r.safety, Safety::Default)
         && eq_opt_coroutine_kind(l.coroutine_kind, r.coroutine_kind)
         && matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
         && eq_ext(&l.ext, &r.ext)
@@ -712,7 +712,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
             both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
         },
         (BareFn(l), BareFn(r)) => {
-            l.unsafety == r.unsafety
+            l.safety == r.safety
                 && eq_ext(&l.ext, &r.ext)
                 && over(&l.generic_params, &r.generic_params, eq_generic_param)
                 && eq_fn_decl(&l.decl, &r.decl)
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 42267310513..553e8999975 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -18,8 +18,8 @@ use rustc_ast::AttrStyle;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem,
-    TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, Safety, TraitItem,
+    TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
 };
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
@@ -207,10 +207,9 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
         ItemKind::Struct(VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")),
         ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
         ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
-        ItemKind::Trait(_, Unsafety::Unsafe, ..)
+        ItemKind::Trait(_, Safety::Unsafe, ..)
         | ItemKind::Impl(Impl {
-            unsafety: Unsafety::Unsafe,
-            ..
+            safety: Safety::Unsafe, ..
         }) => (Pat::Str("unsafe"), Pat::Str("}")),
         ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
         ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
@@ -323,7 +322,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
         TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
         TyKind::BareFn(bare_fn) => (
-            if bare_fn.unsafety == Unsafety::Unsafe {
+            if bare_fn.safety == Safety::Unsafe {
                 Pat::Str("unsafe")
             } else if bare_fn.abi != Abi::Rust {
                 Pat::Str("extern")
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index c921168df29..9f285621e0c 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1082,7 +1082,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::BareFn(bfn) => {
-                bfn.unsafety.hash(&mut self.s);
+                bfn.safety.hash(&mut self.s);
                 bfn.abi.hash(&mut self.s);
                 for arg in bfn.decl.inputs {
                     self.hash_ty(arg);
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index e3ab42c3107..c29e3feac9a 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
+use rustc_hir::{Expr, FnDecl, Safety, LangItem, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::Scalar;
@@ -18,7 +18,7 @@ use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt,
+    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, Upcast, TraitRef, Ty, TyCtxt,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
@@ -311,7 +311,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
         cause: ObligationCause::dummy(),
         param_env,
         recursion_depth: 0,
-        predicate: Binder::dummy(trait_ref).to_predicate(tcx),
+        predicate: trait_ref.upcast(tcx),
     };
     infcx
         .evaluate_obligation(&obligation)
@@ -562,7 +562,7 @@ pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
 /// Returns `true` if the given type is an `unsafe` function.
 pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
+        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).safety() == Safety::Unsafe,
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index a3f3b32ed37..90b56297bb5 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor};
 use rustc_hir::{
     AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath,
-    Stmt, UnOp, UnsafeSource, Unsafety,
+    Safety, Stmt, UnOp, UnsafeSource,
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
@@ -421,16 +421,16 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
                         .map_or(false, |id| {
-                            self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe
+                            self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe
                         }) =>
                 {
                     self.is_unsafe = true;
                 },
                 ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
-                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => {
+                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe => {
                         self.is_unsafe = true;
                     },
-                    ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+                    ty::FnPtr(sig) if sig.safety() == Safety::Unsafe => self.is_unsafe = true,
                     _ => walk_expr(self, e),
                 },
                 ExprKind::Path(ref p)
@@ -452,7 +452,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
         }
         fn visit_nested_item(&mut self, id: ItemId) {
             if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind {
-                self.is_unsafe = i.unsafety == Unsafety::Unsafe;
+                self.is_unsafe = i.safety == Safety::Unsafe;
             }
         }
     }
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index d034826a830..f581204d5f1 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -64,6 +64,12 @@ impl Rustc {
         self
     }
 
+    /// Specify a specific optimization level.
+    pub fn opt_level(&mut self, option: &str) -> &mut Self {
+        self.cmd.arg(format!("-Copt-level={option}"));
+        self
+    }
+
     /// Specify type(s) of output files to generate.
     pub fn emit(&mut self, kinds: &str) -> &mut Self {
         self.cmd.arg(format!("--emit={kinds}"));
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 90e9e58ef9c..e869787b394 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -247,7 +247,7 @@ fn allow_single_line_let_else_block(result: &str, block: &ast::Block) -> bool {
 #[allow(dead_code)]
 #[derive(Debug)]
 struct Item<'a> {
-    unsafety: ast::Unsafe,
+    safety: ast::Safety,
     abi: Cow<'static, str>,
     vis: Option<&'a ast::Visibility>,
     body: Vec<BodyElement<'a>>,
@@ -257,7 +257,7 @@ struct Item<'a> {
 impl<'a> Item<'a> {
     fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
         Item {
-            unsafety: fm.unsafety,
+            safety: fm.safety,
             abi: format_extern(
                 ast::Extern::from_abi(fm.abi, DUMMY_SP),
                 config.force_explicit_abi(),
@@ -290,7 +290,7 @@ pub(crate) struct FnSig<'a> {
     coroutine_kind: Cow<'a, Option<ast::CoroutineKind>>,
     constness: ast::Const,
     defaultness: ast::Defaultness,
-    unsafety: ast::Unsafe,
+    safety: ast::Safety,
     visibility: &'a ast::Visibility,
 }
 
@@ -301,7 +301,7 @@ impl<'a> FnSig<'a> {
         visibility: &'a ast::Visibility,
     ) -> FnSig<'a> {
         FnSig {
-            unsafety: method_sig.header.unsafety,
+            safety: method_sig.header.safety,
             coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
             constness: method_sig.header.constness,
             defaultness: ast::Defaultness::Final,
@@ -330,7 +330,7 @@ impl<'a> FnSig<'a> {
                 constness: fn_sig.header.constness,
                 coroutine_kind: Cow::Borrowed(&fn_sig.header.coroutine_kind),
                 defaultness,
-                unsafety: fn_sig.header.unsafety,
+                safety: fn_sig.header.safety,
                 visibility: vis,
             },
             _ => unreachable!(),
@@ -345,7 +345,7 @@ impl<'a> FnSig<'a> {
         result.push_str(format_constness(self.constness));
         self.coroutine_kind
             .map(|coroutine_kind| result.push_str(format_coro(&coroutine_kind)));
-        result.push_str(format_unsafety(self.unsafety));
+        result.push_str(format_safety(self.safety));
         result.push_str(&format_extern(
             self.ext,
             context.config.force_explicit_abi(),
@@ -356,7 +356,7 @@ impl<'a> FnSig<'a> {
 
 impl<'a> FmtVisitor<'a> {
     fn format_item(&mut self, item: &Item<'_>) {
-        self.buffer.push_str(format_unsafety(item.unsafety));
+        self.buffer.push_str(format_safety(item.safety));
         self.buffer.push_str(&item.abi);
 
         let snippet = self.snippet(item.span);
@@ -924,7 +924,7 @@ fn format_impl_ref_and_type(
     offset: Indent,
 ) -> Option<String> {
     let ast::Impl {
-        unsafety,
+        safety,
         polarity,
         defaultness,
         constness,
@@ -937,7 +937,7 @@ fn format_impl_ref_and_type(
 
     result.push_str(&format_visibility(context, &item.vis));
     result.push_str(format_defaultness(defaultness));
-    result.push_str(format_unsafety(unsafety));
+    result.push_str(format_safety(safety));
 
     let shape = if context.config.version() == Version::Two {
         Shape::indented(offset + last_line_width(&result), context.config)
@@ -1137,7 +1137,7 @@ pub(crate) fn format_trait(
     };
     let ast::Trait {
         is_auto,
-        unsafety,
+        safety,
         ref generics,
         ref bounds,
         ref items,
@@ -1147,7 +1147,7 @@ pub(crate) fn format_trait(
     let header = format!(
         "{}{}{}trait ",
         format_visibility(context, &item.vis),
-        format_unsafety(unsafety),
+        format_safety(safety),
         format_auto(is_auto),
     );
     result.push_str(&header);
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index fe2d28ae1b9..75dea90d994 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -899,7 +899,7 @@ fn rewrite_bare_fn(
         result.push_str("> ");
     }
 
-    result.push_str(crate::utils::format_unsafety(bare_fn.unsafety));
+    result.push_str(crate::utils::format_safety(bare_fn.safety));
 
     result.push_str(&format_extern(
         bare_fn.ext,
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index b91d9b47cb6..09e1dbde1d0 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -108,10 +108,10 @@ pub(crate) fn format_defaultness(defaultness: ast::Defaultness) -> &'static str
 }
 
 #[inline]
-pub(crate) fn format_unsafety(unsafety: ast::Unsafe) -> &'static str {
+pub(crate) fn format_safety(unsafety: ast::Safety) -> &'static str {
     match unsafety {
-        ast::Unsafe::Yes(..) => "unsafe ",
-        ast::Unsafe::No => "",
+        ast::Safety::Unsafe(..) => "unsafe ",
+        ast::Safety::Default => "",
     }
 }
 
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index e1c7dc35087..7a0c68c214c 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -24,7 +24,7 @@ use crate::source_map::{LineRangeUtils, SpanUtils};
 use crate::spanned::Spanned;
 use crate::stmt::Stmt;
 use crate::utils::{
-    self, contains_skip, count_newlines, depr_skip_annotation, format_unsafety, inner_attributes,
+    self, contains_skip, count_newlines, depr_skip_annotation, format_safety, inner_attributes,
     last_line_width, mk_sp, ptr_vec_to_ref_vec, rewrite_ident, starts_with_newline, stmt_expr,
 };
 use crate::{ErrorKind, FormatReport, FormattingError};
@@ -517,9 +517,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                     self.visit_enum(item.ident, &item.vis, def, generics, item.span);
                     self.last_pos = source!(self, item.span).hi();
                 }
-                ast::ItemKind::Mod(unsafety, ref mod_kind) => {
+                ast::ItemKind::Mod(safety, ref mod_kind) => {
                     self.format_missing_with_indent(source!(self, item.span).lo());
-                    self.format_mod(mod_kind, unsafety, &item.vis, item.span, item.ident, attrs);
+                    self.format_mod(mod_kind, safety, &item.vis, item.span, item.ident, attrs);
                 }
                 ast::ItemKind::MacCall(ref mac) => {
                     self.visit_mac(mac, Some(item.ident), MacroPosition::Item);
@@ -913,7 +913,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
     fn format_mod(
         &mut self,
         mod_kind: &ast::ModKind,
-        unsafety: ast::Unsafe,
+        safety: ast::Safety,
         vis: &ast::Visibility,
         s: Span,
         ident: symbol::Ident,
@@ -921,7 +921,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
     ) {
         let vis_str = utils::format_visibility(&self.get_context(), vis);
         self.push_str(&*vis_str);
-        self.push_str(format_unsafety(unsafety));
+        self.push_str(format_safety(safety));
         self.push_str("mod ");
         // Calling `to_owned()` to work around borrow checker.
         let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 1a3d6f8d813..d1ae24007b3 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -103,7 +103,6 @@ run-make/issue-25581/Makefile
 run-make/issue-26006/Makefile
 run-make/issue-26092/Makefile
 run-make/issue-28595/Makefile
-run-make/issue-28766/Makefile
 run-make/issue-30063/Makefile
 run-make/issue-33329/Makefile
 run-make/issue-35164/Makefile
@@ -128,7 +127,6 @@ run-make/issue-85401-static-mir/Makefile
 run-make/issue-85441/Makefile
 run-make/issue-88756-default-output/Makefile
 run-make/issue-97463-abi-param-passing/Makefile
-run-make/issue64319/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/libtest-json/Makefile
@@ -236,10 +234,8 @@ run-make/rlib-format-packed-bundled-libs/Makefile
 run-make/rmeta-preferred/Makefile
 run-make/rustc-macro-dep-files/Makefile
 run-make/rustdoc-io-error/Makefile
-run-make/rustdoc-scrape-examples-invalid-expr/Makefile
 run-make/rustdoc-scrape-examples-macros/Makefile
 run-make/rustdoc-scrape-examples-multiple/Makefile
-run-make/rustdoc-scrape-examples-remap/Makefile
 run-make/rustdoc-scrape-examples-test/Makefile
 run-make/rustdoc-scrape-examples-whitespace/Makefile
 run-make/rustdoc-verify-output-files/Makefile
@@ -264,7 +260,6 @@ run-make/stable-symbol-names/Makefile
 run-make/static-dylib-by-default/Makefile
 run-make/static-extern-type/Makefile
 run-make/static-pie/Makefile
-run-make/static-unwinding/Makefile
 run-make/staticlib-blank-lib/Makefile
 run-make/staticlib-dylib-linkage/Makefile
 run-make/std-core-cycle/Makefile
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index a931782e8cc..6b8106bbc21 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2915,7 +2915,6 @@ ui/macros/issue-95267.rs
 ui/macros/issue-95533.rs
 ui/macros/issue-98466-allow.rs
 ui/macros/issue-98466.rs
-ui/macros/issue-98790.rs
 ui/macros/issue-99261.rs
 ui/macros/issue-99265.rs
 ui/macros/issue-99907.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 94a0eee154d..6e92dab1abc 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -41,6 +41,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
     "tests/ui/macros/not-utf8.bin", // testing including data with the include macros
     "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
     "tests/ui/proc-macro/auxiliary/included-file.txt", // more include
+    "tests/ui/unpretty/auxiliary/data.txt", // more include
     "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
     "tests/ui/sanitizer/dataflow-abilist.txt", // dataflow sanitizer ABI list file
     "tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
index 97d545e0283..32c5be1ec65 100644
--- a/tests/codegen/float/f128.rs
+++ b/tests/codegen/float/f128.rs
@@ -2,6 +2,7 @@
 
 #![crate_type = "lib"]
 #![feature(f128)]
+#![feature(f16)]
 #![feature(core_intrinsics)]
 
 // CHECK-LABEL: i1 @f128_eq(
@@ -127,3 +128,196 @@ pub fn f128_rem_assign(a: &mut f128, b: f128) {
     // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
     *a %= b
 }
+
+/* float to float conversions */
+
+// CHECK-LABEL: half @f128_as_f16(
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: float @f128_as_f32(
+#[no_mangle]
+pub fn f128_as_f32(a: f128) -> f32 {
+    // CHECK: fptrunc fp128 %{{.+}} to float
+    a as f32
+}
+
+// CHECK-LABEL: double @f128_as_f64(
+#[no_mangle]
+pub fn f128_as_f64(a: f128) -> f64 {
+    // CHECK: fptrunc fp128 %{{.+}} to double
+    a as f64
+}
+
+// CHECK-LABEL: fp128 @f128_as_self(
+#[no_mangle]
+pub fn f128_as_self(a: f128) -> f128 {
+    // CHECK: ret fp128 %{{.+}}
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f16_as_f128(
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f32_as_f128(
+#[no_mangle]
+pub fn f32_as_f128(a: f32) -> f128 {
+    // CHECK: fpext float %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f64_as_f128(
+#[no_mangle]
+pub fn f64_as_f128(a: f64) -> f128 {
+    // CHECK: fpext double %{{.+}} to fp128
+    a as f128
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f128_as_u8(
+#[no_mangle]
+pub fn f128_as_u8(a: f128) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f128_as_u16(a: f128) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f128_as_u32(
+#[no_mangle]
+pub fn f128_as_u32(a: f128) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f128_as_u64(
+#[no_mangle]
+pub fn f128_as_u64(a: f128) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}})
+    a as u64
+}
+
+// CHECK-LABEL: i128 @f128_as_u128(
+#[no_mangle]
+pub fn f128_as_u128(a: f128) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f128_as_i8(
+#[no_mangle]
+pub fn f128_as_i8(a: f128) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f128_as_i16(
+#[no_mangle]
+pub fn f128_as_i16(a: f128) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f128_as_i32(
+#[no_mangle]
+pub fn f128_as_i32(a: f128) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f128_as_i64(
+#[no_mangle]
+pub fn f128_as_i64(a: f128) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}})
+    a as i64
+}
+
+// CHECK-LABEL: i128 @f128_as_i128(
+#[no_mangle]
+pub fn f128_as_i128(a: f128) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// CHECK-LABEL: fp128 @u8_as_f128(
+#[no_mangle]
+pub fn u8_as_f128(a: u8) -> f128 {
+    // CHECK: uitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u16_as_f128(
+#[no_mangle]
+pub fn u16_as_f128(a: u16) -> f128 {
+    // CHECK: uitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u32_as_f128(
+#[no_mangle]
+pub fn u32_as_f128(a: u32) -> f128 {
+    // CHECK: uitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u64_as_f128(
+#[no_mangle]
+pub fn u64_as_f128(a: u64) -> f128 {
+    // CHECK: uitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u128_as_f128(
+#[no_mangle]
+pub fn u128_as_f128(a: u128) -> f128 {
+    // CHECK: uitofp i128 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i8_as_f128(
+#[no_mangle]
+pub fn i8_as_f128(a: i8) -> f128 {
+    // CHECK: sitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i16_as_f128(
+#[no_mangle]
+pub fn i16_as_f128(a: i16) -> f128 {
+    // CHECK: sitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i32_as_f128(
+#[no_mangle]
+pub fn i32_as_f128(a: i32) -> f128 {
+    // CHECK: sitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i64_as_f128(
+#[no_mangle]
+pub fn i64_as_f128(a: i64) -> f128 {
+    // CHECK: sitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i128_as_f128(
+#[no_mangle]
+pub fn i128_as_f128(a: i128) -> f128 {
+    // CHECK: sitofp i128 %{{.+}} to fp128
+    a as f128
+}
diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs
index d1f75cc3b68..96daac869c2 100644
--- a/tests/codegen/float/f16.rs
+++ b/tests/codegen/float/f16.rs
@@ -1,9 +1,12 @@
 // Verify that our intrinsics generate the correct LLVM calls for f16
 
 #![crate_type = "lib"]
+#![feature(f128)]
 #![feature(f16)]
 #![feature(core_intrinsics)]
 
+/* arithmetic */
+
 // CHECK-LABEL: i1 @f16_eq(
 #[no_mangle]
 pub fn f16_eq(a: f16, b: f16) -> bool {
@@ -109,7 +112,7 @@ pub fn f16_sub_assign(a: &mut f16, b: f16) {
 pub fn f16_mul_assign(a: &mut f16, b: f16) {
     // CHECK: fmul half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a *= b
+    *a *= b;
 }
 
 // CHECK-LABEL: void @f16_div_assign(
@@ -117,7 +120,7 @@ pub fn f16_mul_assign(a: &mut f16, b: f16) {
 pub fn f16_div_assign(a: &mut f16, b: f16) {
     // CHECK: fdiv half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a /= b
+    *a /= b;
 }
 
 // CHECK-LABEL: void @f16_rem_assign(
@@ -125,5 +128,198 @@ pub fn f16_div_assign(a: &mut f16, b: f16) {
 pub fn f16_rem_assign(a: &mut f16, b: f16) {
     // CHECK: frem half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a %= b
+    *a %= b;
+}
+
+/* float to float conversions */
+
+// CHECK-LABEL: half @f16_as_self(
+#[no_mangle]
+pub fn f16_as_self(a: f16) -> f16 {
+    // CHECK: ret half %{{.+}}
+    a as f16
+}
+
+// CHECK-LABEL: float @f16_as_f32(
+#[no_mangle]
+pub fn f16_as_f32(a: f16) -> f32 {
+    // CHECK: fpext half %{{.+}} to float
+    a as f32
+}
+
+// CHECK-LABEL: double @f16_as_f64(
+#[no_mangle]
+pub fn f16_as_f64(a: f16) -> f64 {
+    // CHECK: fpext half %{{.+}} to double
+    a as f64
+}
+
+// CHECK-LABEL: fp128 @f16_as_f128(
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: half @f32_as_f16(
+#[no_mangle]
+pub fn f32_as_f16(a: f32) -> f16 {
+    // CHECK: fptrunc float %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @f64_as_f16(
+#[no_mangle]
+pub fn f64_as_f16(a: f64) -> f16 {
+    // CHECK: fptrunc double %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @f128_as_f16(
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f16_as_u8(
+#[no_mangle]
+pub fn f16_as_u8(a: f16) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f16(half %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f16_as_u16(a: f16) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f16(half %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f16_as_u32(
+#[no_mangle]
+pub fn f16_as_u32(a: f16) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f16(half %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f16_as_u64(
+#[no_mangle]
+pub fn f16_as_u64(a: f16) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f16(half %{{.+}})
+    a as u64
+}
+
+// CHECK-LABEL: i128 @f16_as_u128(
+#[no_mangle]
+pub fn f16_as_u128(a: f16) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f16(half %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f16_as_i8(
+#[no_mangle]
+pub fn f16_as_i8(a: f16) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f16(half %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f16_as_i16(
+#[no_mangle]
+pub fn f16_as_i16(a: f16) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f16(half %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f16_as_i32(
+#[no_mangle]
+pub fn f16_as_i32(a: f16) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f16(half %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f16_as_i64(
+#[no_mangle]
+pub fn f16_as_i64(a: f16) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f16(half %{{.+}})
+    a as i64
+}
+
+// CHECK-LABEL: i128 @f16_as_i128(
+#[no_mangle]
+pub fn f16_as_i128(a: f16) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f16(half %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// CHECK-LABEL: half @u8_as_f16(
+#[no_mangle]
+pub fn u8_as_f16(a: u8) -> f16 {
+    // CHECK: uitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u16_as_f16(
+#[no_mangle]
+pub fn u16_as_f16(a: u16) -> f16 {
+    // CHECK: uitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u32_as_f16(
+#[no_mangle]
+pub fn u32_as_f16(a: u32) -> f16 {
+    // CHECK: uitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u64_as_f16(
+#[no_mangle]
+pub fn u64_as_f16(a: u64) -> f16 {
+    // CHECK: uitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u128_as_f16(
+#[no_mangle]
+pub fn u128_as_f16(a: u128) -> f16 {
+    // CHECK: uitofp i128 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i8_as_f16(
+#[no_mangle]
+pub fn i8_as_f16(a: i8) -> f16 {
+    // CHECK: sitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i16_as_f16(
+#[no_mangle]
+pub fn i16_as_f16(a: i16) -> f16 {
+    // CHECK: sitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i32_as_f16(
+#[no_mangle]
+pub fn i32_as_f16(a: i32) -> f16 {
+    // CHECK: sitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i64_as_f16(
+#[no_mangle]
+pub fn i64_as_f16(a: i64) -> f16 {
+    // CHECK: sitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i128_as_f16(
+#[no_mangle]
+pub fn i128_as_f16(a: i128) -> f16 {
+    // CHECK: sitofp i128 %{{.+}} to half
+    a as f16
 }
diff --git a/tests/codegen/intrinsics/aggregate-thin-pointer.rs b/tests/codegen/intrinsics/aggregate-thin-pointer.rs
new file mode 100644
index 00000000000..aa3bf7e8b14
--- /dev/null
+++ b/tests/codegen/intrinsics/aggregate-thin-pointer.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -O -C no-prepopulate-passes -Z mir-enable-passes=-InstSimplify
+//@ only-64bit (so I don't need to worry about usize)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::aggregate_raw_ptr;
+
+// InstSimplify replaces these with casts if it can, which means they're almost
+// never seen in codegen, but PR#121571 found a way, so add a test for it.
+
+#[inline(never)]
+pub fn opaque(_p: &*const i32) {}
+
+// CHECK-LABEL: @thin_ptr_via_aggregate(
+#[no_mangle]
+pub unsafe fn thin_ptr_via_aggregate(p: *const ()) {
+    // CHECK: %mem = alloca
+    // CHECK: store ptr %p, ptr %mem
+    // CHECK: call {{.+}}aggregate_thin_pointer{{.+}} %mem)
+    let mem = aggregate_raw_ptr(p, ());
+    opaque(&mem);
+}
diff --git a/tests/debuginfo/empty-string.rs b/tests/debuginfo/empty-string.rs
index 36240730e19..35b68ed91c0 100644
--- a/tests/debuginfo/empty-string.rs
+++ b/tests/debuginfo/empty-string.rs
@@ -23,7 +23,7 @@
 // lldb-check:[...] empty_string = "" { vec = size=0 }
 
 // lldb-command:fr v empty_str
-// lldb-check:[...] empty_str = "" { data_ptr = [...] length = 0 }
+// lldb-check:[...] empty_str = ""
 
 fn main() {
     let empty_string = String::new();
diff --git a/tests/debuginfo/pretty-slices.rs b/tests/debuginfo/pretty-slices.rs
index 5d2086fa478..9defa344be0 100644
--- a/tests/debuginfo/pretty-slices.rs
+++ b/tests/debuginfo/pretty-slices.rs
@@ -27,10 +27,10 @@
 // lldb-check:(&mut [i32]) mut_slice = size=4 { [0] = 2 [1] = 3 [2] = 5 [3] = 7 }
 
 // lldb-command:v str_slice
-// lldb-check:(&str) str_slice = "string slice" { data_ptr = [...] length = 12 }
+// lldb-check:(&str) str_slice = "string slice" { [0] = 's' [1] = 't' [2] = 'r' [3] = 'i' [4] = 'n' [5] = 'g' [6] = ' ' [7] = 's' [8] = 'l' [9] = 'i' [10] = 'c' [11] = 'e' }
 
 // lldb-command:v mut_str_slice
-// lldb-check:(&mut str) mut_str_slice = "mutable string slice" { data_ptr = [...] length = 20 }
+// lldb-check:(&mut str) mut_str_slice = "mutable string slice" { [0] = 'm' [1] = 'u' [2] = 't' [3] = 'a' [4] = 'b' [5] = 'l' [6] = 'e' [7] = ' ' [8] = 's' [9] = 't' [10] = 'r' [11] = 'i' [12] = 'n' [13] = 'g' [14] = ' ' [15] = 's' [16] = 'l' [17] = 'i' [18] = 'c' [19] = 'e' }
 
 fn b() {}
 
diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs
new file mode 100644
index 00000000000..48d40d167ba
--- /dev/null
+++ b/tests/debuginfo/strings-and-strs.rs
@@ -0,0 +1,63 @@
+//@ min-gdb-version: 14.0
+//@ min-lldb-version: 1800
+
+//@ compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+// gdb-command:run
+
+// gdb-command:print plain_string
+// gdbr-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x55555555ab80}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (5), alloc: alloc::alloc::Global}, len: 5}}
+
+// gdb-command:print plain_str
+// gdbr-check:$2 = "Hello"
+
+// gdb-command:print str_in_struct
+// gdbr-check:$3 = strings_and_strs::Foo {inner: "Hello"}
+
+// gdb-command:print str_in_tuple
+// gdbr-check:$4 = ("Hello", "World")
+
+// gdb-command:print str_in_rc
+// gdbr-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull<alloc::rc::RcBox<&str>> {pointer: 0x55555555aae0}, phantom: core::marker::PhantomData<alloc::rc::RcBox<&str>>, alloc: alloc::alloc::Global}
+
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+// lldb-command:v plain_string
+// lldbg-check:(alloc::string::String) plain_string = "Hello" { vec = size=5 { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
+
+// lldb-command:v plain_str
+// lldbg-check:(&str) plain_str = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' }
+
+// lldb-command:v str_in_struct
+// lldbg-check:((&str, &str)) str_in_tuple = { 0 = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } 1 = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } }
+
+// lldb-command:v str_in_tuple
+// lldbg-check:((&str, &str)) str_in_tuple = { 0 = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } 1 = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } }
+
+// lldb-command:v str_in_rc
+// lldbg-check:(alloc::rc::Rc<&str, alloc::alloc::Global>) str_in_rc = strong=1, weak=0 { value = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
+
+
+#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+pub struct Foo<'a> {
+    inner: &'a str,
+}
+
+fn main() {
+    let plain_string = String::from("Hello");
+    let plain_str = "Hello";
+    let str_in_struct = Foo { inner: "Hello" };
+    let str_in_tuple = ("Hello", "World");
+
+    let str_in_rc = std::rc::Rc::new("Hello");
+    zzz(); // #break
+}
+
+fn zzz() {
+    ()
+}
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index 68cb4d55e7b..25d0e5ccf49 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -69,9 +69,9 @@
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
--         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -87,9 +87,9 @@
 +         nop;
           StorageLive(_13);
 -         _13 = _7;
--         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index fa184348b3b..3c5fd944d6b 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -69,9 +69,9 @@
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
--         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -87,9 +87,9 @@
 +         nop;
           StorageLive(_13);
 -         _13 = _7;
--         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index d7372a05082..a35af43cefd 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -105,7 +105,7 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe)));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index 6ec62bfcf8c..2495719ec1c 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -105,7 +105,7 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe)));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/run-make/issue-28766/foo.rs b/tests/run-make/box-struct-no-segfault/foo.rs
index 1dcabe42dc1..1dcabe42dc1 100644
--- a/tests/run-make/issue-28766/foo.rs
+++ b/tests/run-make/box-struct-no-segfault/foo.rs
diff --git a/tests/run-make/issue-28766/main.rs b/tests/run-make/box-struct-no-segfault/main.rs
index de12b1fd9dc..de12b1fd9dc 100644
--- a/tests/run-make/issue-28766/main.rs
+++ b/tests/run-make/box-struct-no-segfault/main.rs
diff --git a/tests/run-make/box-struct-no-segfault/rmake.rs b/tests/run-make/box-struct-no-segfault/rmake.rs
new file mode 100644
index 00000000000..5406f765e6c
--- /dev/null
+++ b/tests/run-make/box-struct-no-segfault/rmake.rs
@@ -0,0 +1,13 @@
+// The crate "foo" tied to this test executes a very specific function,
+// which involves boxing an instance of the struct Foo. However,
+// this once caused a segmentation fault in cargo release builds due to an LLVM
+// incorrect assertion.
+// This test checks that this bug does not resurface.
+// See https://github.com/rust-lang/rust/issues/28766
+
+use run_make_support::{rustc, tmp_dir};
+
+fn main() {
+    rustc().opt().input("foo.rs").run();
+    rustc().opt().library_search_path(tmp_dir()).input("main.rs").run();
+}
diff --git a/tests/run-make/issue-28766/Makefile b/tests/run-make/issue-28766/Makefile
deleted file mode 100644
index 96d0bdc2b2a..00000000000
--- a/tests/run-make/issue-28766/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) -O foo.rs
-	$(RUSTC) -O -L $(TMPDIR) main.rs
diff --git a/tests/run-make/issue64319/Makefile b/tests/run-make/issue64319/Makefile
deleted file mode 100644
index 56346cbcc15..00000000000
--- a/tests/run-make/issue64319/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# Different optimization levels imply different values for `-Zshare-generics`,
-# so try out a whole bunch of combinations to make sure everything is compatible
-all:
-	# First up, try some defaults
-	$(RUSTC) --crate-type rlib foo.rs
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3
-
-	# Next try mixing up some things explicitly
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
-
-	# Now combine a whole bunch of options together
-	$(RUSTC) --crate-type rlib foo.rs
-	$(RUSTC) --crate-type dylib bar.rs
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=yes
diff --git a/tests/run-make/rust-lld-by-default/main.rs b/tests/run-make/rust-lld-by-default/main.rs
new file mode 100644
index 00000000000..e9f655fc09e
--- /dev/null
+++ b/tests/run-make/rust-lld-by-default/main.rs
@@ -0,0 +1,5 @@
+// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
+// target.
+// See https://github.com/rust-lang/compiler-team/issues/510 for more info
+
+fn main() {}
diff --git a/tests/run-make/rust-lld-by-default/rmake.rs b/tests/run-make/rust-lld-by-default/rmake.rs
new file mode 100644
index 00000000000..876968727f3
--- /dev/null
+++ b/tests/run-make/rust-lld-by-default/rmake.rs
@@ -0,0 +1,43 @@
+// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`, and that it can
+// also be turned off with a CLI flag.
+
+//@ needs-rust-lld
+//@ only-x86_64-unknown-linux-gnu
+
+extern crate run_make_support;
+
+use run_make_support::regex::Regex;
+use run_make_support::rustc;
+use std::process::Output;
+
+fn main() {
+    // A regular compilation should use rust-lld by default. We'll check that by asking the linker
+    // to display its version number with a link-arg.
+    let output = rustc()
+        .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
+        .link_arg("-Wl,-v")
+        .input("main.rs")
+        .run();
+    assert!(
+        find_lld_version_in_logs(output),
+        "the LLD version string should be present in the output logs"
+    );
+
+    // But it can still be disabled by turning the linker feature off.
+    let output = rustc()
+        .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
+        .link_arg("-Wl,-v")
+        .arg("-Zlinker-features=-lld")
+        .input("main.rs")
+        .run();
+    assert!(
+        !find_lld_version_in_logs(output),
+        "the LLD version string should not be present in the output logs"
+    );
+}
+
+fn find_lld_version_in_logs(output: Output) -> bool {
+    let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
+    let stderr = std::str::from_utf8(&output.stderr).unwrap();
+    stderr.lines().any(|line| lld_version_re.is_match(line))
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-invalid-expr/Makefile b/tests/run-make/rustdoc-scrape-examples-invalid-expr/Makefile
deleted file mode 100644
index 7786ff762cb..00000000000
--- a/tests/run-make/rustdoc-scrape-examples-invalid-expr/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
new file mode 100644
index 00000000000..537d3e2d724
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape();
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
index 1bc23ec8881..537d3e2d724 100644
--- a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
@@ -1,49 +1,6 @@
-use run_make_support::{htmldocck, rustc, rustdoc, source_path, tmp_dir};
-use std::fs::read_dir;
-use std::path::Path;
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
 
 fn main() {
-    let lib_dir = tmp_dir();
-    let out_dir = tmp_dir().join("rustdoc");
-    let crate_name = "foobar";
-    let deps = read_dir("examples")
-        .unwrap()
-        .filter_map(|entry| entry.ok().map(|e| e.path()))
-        .filter(|path| path.is_file() && path.extension().is_some_and(|ext| ext == "rs"))
-        .collect::<Vec<_>>();
-
-    rustc().input("src/lib.rs").crate_name(crate_name).crate_type("lib").emit("metadata").run();
-
-    let mut out_deps = Vec::with_capacity(deps.len());
-    for dep in deps {
-        let dep_stem = dep.file_stem().unwrap();
-        let out_example = out_dir.join(format!("{}.calls", dep_stem.to_str().unwrap()));
-        rustdoc()
-            .input(&dep)
-            .crate_name(&dep_stem)
-            .crate_type("bin")
-            .output(&out_dir)
-            .extern_(crate_name, lib_dir.join(format!("lib{crate_name}.rmeta")))
-            .arg("-Zunstable-options")
-            .arg("--scrape-examples-output-path")
-            .arg(&out_example)
-            .arg("--scrape-examples-target-crate")
-            .arg(crate_name)
-            .run();
-        out_deps.push(out_example);
-    }
-
-    let mut rustdoc = rustdoc();
-    rustdoc
-        .input("src/lib.rs")
-        .output(&out_dir)
-        .crate_name(crate_name)
-        .crate_type("lib")
-        .arg("-Zunstable-options");
-    for dep in out_deps {
-        rustdoc.arg("--with-examples").arg(dep);
-    }
-    rustdoc.run();
-
-    assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
+    scrape::scrape();
 }
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/Makefile b/tests/run-make/rustdoc-scrape-examples-remap/Makefile
deleted file mode 100644
index 7786ff762cb..00000000000
--- a/tests/run-make/rustdoc-scrape-examples-remap/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
new file mode 100644
index 00000000000..d9deaf279ce
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
@@ -0,0 +1,5 @@
+mod scrape;
+
+fn main() {
+    scrape::scrape();
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
new file mode 100644
index 00000000000..709388b5492
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
@@ -0,0 +1,49 @@
+use run_make_support::{htmldocck, rustc, rustdoc, source_path, tmp_dir};
+use std::fs::read_dir;
+use std::path::Path;
+
+pub fn scrape() {
+    let lib_dir = tmp_dir();
+    let out_dir = tmp_dir().join("rustdoc");
+    let crate_name = "foobar";
+    let deps = read_dir("examples")
+        .unwrap()
+        .filter_map(|entry| entry.ok().map(|e| e.path()))
+        .filter(|path| path.is_file() && path.extension().is_some_and(|ext| ext == "rs"))
+        .collect::<Vec<_>>();
+
+    rustc().input("src/lib.rs").crate_name(crate_name).crate_type("lib").emit("metadata").run();
+
+    let mut out_deps = Vec::with_capacity(deps.len());
+    for dep in deps {
+        let dep_stem = dep.file_stem().unwrap();
+        let out_example = out_dir.join(format!("{}.calls", dep_stem.to_str().unwrap()));
+        rustdoc()
+            .input(&dep)
+            .crate_name(&dep_stem)
+            .crate_type("bin")
+            .output(&out_dir)
+            .extern_(crate_name, lib_dir.join(format!("lib{crate_name}.rmeta")))
+            .arg("-Zunstable-options")
+            .arg("--scrape-examples-output-path")
+            .arg(&out_example)
+            .arg("--scrape-examples-target-crate")
+            .arg(crate_name)
+            .run();
+        out_deps.push(out_example);
+    }
+
+    let mut rustdoc = rustdoc();
+    rustdoc
+        .input("src/lib.rs")
+        .output(&out_dir)
+        .crate_name(crate_name)
+        .crate_type("lib")
+        .arg("-Zunstable-options");
+    for dep in out_deps {
+        rustdoc.arg("--with-examples").arg(dep);
+    }
+    rustdoc.run();
+
+    assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
+}
diff --git a/tests/run-make/issue64319/bar.rs b/tests/run-make/share-generics-export-again/bar.rs
index 3895c0b6cdb..3895c0b6cdb 100644
--- a/tests/run-make/issue64319/bar.rs
+++ b/tests/run-make/share-generics-export-again/bar.rs
diff --git a/tests/run-make/issue64319/foo.rs b/tests/run-make/share-generics-export-again/foo.rs
index c54a238e9ad..c54a238e9ad 100644
--- a/tests/run-make/issue64319/foo.rs
+++ b/tests/run-make/share-generics-export-again/foo.rs
diff --git a/tests/run-make/share-generics-export-again/rmake.rs b/tests/run-make/share-generics-export-again/rmake.rs
new file mode 100644
index 00000000000..b9964eb442a
--- /dev/null
+++ b/tests/run-make/share-generics-export-again/rmake.rs
@@ -0,0 +1,45 @@
+// When crates had different optimization levels, a bug caused
+// incorrect symbol name generations. -Z share-generics could
+// also fail to re-export upstream generics on multiple compile
+// runs of the same dynamic library.
+
+// This test repeatedly compiles an rlib and a dylib with these flags
+// to check if this bug ever returns.
+
+// See https://github.com/rust-lang/rust/pull/68277
+// See https://github.com/rust-lang/rust/issues/64319
+//@ ignore-cross-compile
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc().crate_type("rlib").input("foo.rs").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("rlib").input("foo.rs").run();
+    rustc().crate_type("dylib").input("bar.rs").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("1").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("1").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("1").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("2").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("2").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("2").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("s").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("s").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("s").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("z").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("z").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("z").arg("-Zshare-generics=yes").run();
+}
diff --git a/tests/run-make/static-unwinding/Makefile b/tests/run-make/static-unwinding/Makefile
deleted file mode 100644
index 4b093f93608..00000000000
--- a/tests/run-make/static-unwinding/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# ignore-cross-compile
-# needs-unwind
-include ../tools.mk
-
-all:
-	$(RUSTC) lib.rs
-	$(RUSTC) main.rs
-	$(call RUN,main)
diff --git a/tests/run-make/static-unwinding/rmake.rs b/tests/run-make/static-unwinding/rmake.rs
new file mode 100644
index 00000000000..ee3d9a342f9
--- /dev/null
+++ b/tests/run-make/static-unwinding/rmake.rs
@@ -0,0 +1,15 @@
+// During unwinding, an implementation of Drop is possible to clean up resources.
+// This test implements drop in both a main function and its static library.
+// If the test succeeds, a Rust program being a static library does not affect Drop implementations.
+// See https://github.com/rust-lang/rust/issues/10434
+
+//@ ignore-cross-compile
+//@ needs-unwind
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    rustc().input("lib.rs").run();
+    rustc().input("main.rs").run();
+    run("main");
+}
diff --git a/tests/run-make/stdin-rustdoc/rmake.rs b/tests/run-make/stdin-rustdoc/rmake.rs
new file mode 100644
index 00000000000..584a610ed63
--- /dev/null
+++ b/tests/run-make/stdin-rustdoc/rmake.rs
@@ -0,0 +1,25 @@
+//! This test checks rustdoc `-` (stdin) handling
+
+use run_make_support::{rustdoc, tmp_dir};
+
+static INPUT: &str = r#"
+//! ```
+//! dbg!(());
+//! ```
+pub struct F;
+"#;
+
+fn main() {
+    let tmp_dir = tmp_dir();
+    let out_dir = tmp_dir.join("doc");
+
+    // rustdoc -
+    rustdoc().arg("-").out_dir(&out_dir).stdin(INPUT).run();
+    assert!(out_dir.join("rust_out/struct.F.html").try_exists().unwrap());
+
+    // rustdoc --test -
+    rustdoc().arg("--test").arg("-").stdin(INPUT).run();
+
+    // rustdoc file.rs -
+    rustdoc().arg("file.rs").arg("-").run_fail();
+}
diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
index 77fbaf52934..bf53089675d 100644
--- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
+++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
@@ -1,8 +1,11 @@
-error: the type `Foo::Bar<Vec<[u32]>>` is not well-formed
-  --> $DIR/wf-check-skipped.rs:17:14
+error[E0277]: the size for values of type `[u32]` cannot be known at compilation time
+  --> $DIR/wf-check-skipped.rs:17:25
    |
 LL | fn main() -> Foo::Bar::<Vec<[u32]>> {}
-   |              ^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u32]`
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
index 5b812a2295e..52df4efd13e 100644
--- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
+++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
@@ -15,4 +15,4 @@ impl Foo {
 }
 
 fn main() -> Foo::Bar::<Vec<[u32]>> {}
-//[next]~^ ERROR the type `Foo::Bar<Vec<[u32]>>` is not well-formed
+//[next]~^ ERROR the size for values of type `[u32]` cannot be known at compilation time
diff --git a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs
index f213e8933bf..85c08ec035e 100644
--- a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs
+++ b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs
@@ -1,4 +1,15 @@
 const X: i32 = #[allow(dead_code)] 8;
 //~^ ERROR attributes on expressions are experimental
 
+const Y: i32 =
+    /// foo
+//~^ ERROR attributes on expressions are experimental
+    8;
+
+const Z: i32 = {
+    //! foo
+//~^ ERROR attributes on expressions are experimental
+    8
+};
+
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr
index 67fdae030c0..14f7d58e47a 100644
--- a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr
+++ b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr
@@ -8,6 +8,28 @@ LL | const X: i32 = #[allow(dead_code)] 8;
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 1 previous error
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/feature-gate-stmt_expr_attributes.rs:5:5
+   |
+LL |     /// foo
+   |     ^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: `///` is used for outer documentation comments; for a plain comment, use `//`
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/feature-gate-stmt_expr_attributes.rs:10:5
+   |
+LL |     //! foo
+   |     ^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr
index 6855e17df9a..98609211865 100644
--- a/tests/ui/for/issue-20605.next.stderr
+++ b/tests/ui/for/issue-20605.next.stderr
@@ -11,31 +11,13 @@ help: consider mutably borrowing here
 LL |     for item in &mut *things { *item = 0 }
    |                 ++++
 
-error: the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-  --> $DIR/issue-20605.rs:6:17
-   |
-LL |     for item in *things { *item = 0 }
-   |                 ^^^^^^^
-
-error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-  --> $DIR/issue-20605.rs:6:17
-   |
-LL |     for item in *things { *item = 0 }
-   |                 ^^^^^^^
-
-error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
-  --> $DIR/issue-20605.rs:6:17
-   |
-LL |     for item in *things { *item = 0 }
-   |                 ^^^^^^^
-
 error[E0614]: type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced
   --> $DIR/issue-20605.rs:6:27
    |
 LL |     for item in *things { *item = 0 }
    |                           ^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs
index b923a7088fe..647dc84028c 100644
--- a/tests/ui/for/issue-20605.rs
+++ b/tests/ui/for/issue-20605.rs
@@ -6,9 +6,6 @@ fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) {
     for item in *things { *item = 0 }
     //[current]~^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
     //[next]~^^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
-    //[next]~| ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-    //[next]~| ERROR the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-    //[next]~| ERROR the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
     //[next]~| ERROR type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced
 
     // FIXME(-Znext-solver): these error messages are horrible and have to be
diff --git a/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs
new file mode 100644
index 00000000000..96a0f2f40bf
--- /dev/null
+++ b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs
@@ -0,0 +1,19 @@
+// Fix for <https://github.com/rust-lang/rust/issues/125196>.
+//@ check-pass
+
+trait Tr {
+    type Gat<T>;
+}
+
+struct W<T>(T);
+
+fn foo<T: Tr>() where for<'a> &'a T: Tr<Gat<W<i32>> = i32> {
+    let x: <&T as Tr>::Gat<W<_>> = 1i32;
+    // Previously, `match_projection_projections` only checked that
+    // `shallow_resolve(W<?0>) = W<?0>`. This won't prevent *all* inference guidance
+    // from projection predicates in the environment, just ones that guide the
+    // outermost type of each GAT constructor. This is definitely wrong, but there is
+    // code that relies on it in the wild :/
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
index 365955166e6..5a6bf9bfaef 100644
--- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
@@ -14,6 +14,6 @@ struct W<T>(T);
 // `usize: Foo` doesn't hold. Therefore we ICE, because we don't expect to still
 // encounter weak types in `assemble_alias_bound_candidates_recur`.
 fn hello(_: W<A<usize>>) {}
-//~^ ERROR the type `W<A<usize>>` is not well-formed
+//~^ ERROR the size for values of type `A<usize>` cannot be known at compilation time
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
index 5df27ac3bc6..9663fab3d8c 100644
--- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
@@ -7,11 +7,14 @@ LL | #![feature(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
 
-error: the type `W<A<usize>>` is not well-formed
+error[E0277]: the size for values of type `A<usize>` cannot be known at compilation time
   --> $DIR/alias-bounds-when-not-wf.rs:16:13
    |
 LL | fn hello(_: W<A<usize>>) {}
-   |             ^^^^^^^^^^^
+   |             ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `A<usize>`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
index 2e0812d6472..d73d5bab8d7 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
@@ -22,7 +22,7 @@ error[E0308]: intrinsic has wrong type
   --> $DIR/safe-intrinsic-mismatch.rs:11:16
    |
 LL | const fn assume(_b: bool) {}
-   |                ^ expected unsafe fn, found normal fn
+   |                ^ expected unsafe fn, found safe fn
    |
    = note: expected signature `unsafe fn(_)`
               found signature `fn(_)`
@@ -37,7 +37,7 @@ error[E0308]: intrinsic has wrong type
   --> $DIR/safe-intrinsic-mismatch.rs:15:26
    |
 LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
-   |                          ^ expected unsafe fn, found normal fn
+   |                          ^ expected unsafe fn, found safe fn
    |
    = note: expected signature `unsafe fn(_, _, _)`
               found signature `fn(_, _, _)`
diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr
index add85b2f5e0..1ff5c8d8825 100644
--- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr
+++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr
@@ -13,7 +13,7 @@ LL |     (/// useless doc comment
    = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: `///` is for documentation comments. For a plain comment, use `//`.
+   = help: `///` is used for outer documentation comments; for a plain comment, use `//`
 
 error: unused doc comment
   --> $DIR/unused-doc-comments-edge-cases.rs:6:9
diff --git a/tests/ui/lint/unused/unused-macro-rules-compile-error.rs b/tests/ui/lint/unused/unused-macro-rules-compile-error.rs
index 4d51db89bc0..0c8fe65bd5c 100644
--- a/tests/ui/lint/unused/unused-macro-rules-compile-error.rs
+++ b/tests/ui/lint/unused/unused-macro-rules-compile-error.rs
@@ -9,7 +9,7 @@ macro_rules! num {
     // Some nested use
     (two_) => { foo(compile_error!("foo")); };
     (three) => { 3 };
-    (four) => { 4 }; //~ ERROR: rule of macro
+    (four) => { 4 }; //~ ERROR: rule #5 of macro
 }
 const _NUM: u8 = num!(one) + num!(three);
 
@@ -17,9 +17,9 @@ const _NUM: u8 = num!(one) + num!(three);
 macro_rules! num2 {
     (one) => { 1 };
     // Only identifier present
-    (two) => { fn compile_error() {} }; //~ ERROR: rule of macro
+    (two) => { fn compile_error() {} }; //~ ERROR: rule #2 of macro
     // Only identifier and bang present
-    (two_) => { compile_error! }; //~ ERROR: rule of macro
+    (two_) => { compile_error! }; //~ ERROR: rule #3 of macro
     (three) => { 3 };
 }
 const _NUM2: u8 = num2!(one) + num2!(three);
diff --git a/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr b/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr
index 76af8c967db..936428f6a1c 100644
--- a/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr
+++ b/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr
@@ -1,4 +1,4 @@
-error: 5th rule of macro `num` is never used
+error: rule #5 of macro `num` is never used
   --> $DIR/unused-macro-rules-compile-error.rs:12:5
    |
 LL |     (four) => { 4 };
@@ -10,13 +10,13 @@ note: the lint level is defined here
 LL | #![deny(unused_macro_rules)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: 3rd rule of macro `num2` is never used
+error: rule #3 of macro `num2` is never used
   --> $DIR/unused-macro-rules-compile-error.rs:22:5
    |
 LL |     (two_) => { compile_error! };
    |     ^^^^^^
 
-error: 2nd rule of macro `num2` is never used
+error: rule #2 of macro `num2` is never used
   --> $DIR/unused-macro-rules-compile-error.rs:20:5
    |
 LL |     (two) => { fn compile_error() {} };
diff --git a/tests/ui/lint/unused/unused-macro-rules-decl.rs b/tests/ui/lint/unused/unused-macro-rules-decl.rs
index 537c84940fd..ca14d58e524 100644
--- a/tests/ui/lint/unused/unused-macro-rules-decl.rs
+++ b/tests/ui/lint/unused/unused-macro-rules-decl.rs
@@ -6,9 +6,9 @@
 // Most simple case
 macro num {
     (one) => { 1 },
-    (two) => { 2 }, //~ ERROR: 2nd rule of macro
+    (two) => { 2 }, //~ ERROR: rule #2 of macro
     (three) => { 3 },
-    (four) => { 4 }, //~ ERROR: 4th rule of macro
+    (four) => { 4 }, //~ ERROR: rule #4 of macro
 }
 const _NUM: u8 = num!(one) + num!(three);
 
@@ -28,7 +28,7 @@ macro num_rec {
     (two) => {
         num_rec!(one) + num_rec!(one)
     },
-    (three) => { //~ ERROR: 3rd rule of macro
+    (three) => { //~ ERROR: rule #3 of macro
         num_rec!(one) + num_rec!(two)
     },
     (four) => {
diff --git a/tests/ui/lint/unused/unused-macro-rules-decl.stderr b/tests/ui/lint/unused/unused-macro-rules-decl.stderr
index 4d9b22feda2..10ceb3921f3 100644
--- a/tests/ui/lint/unused/unused-macro-rules-decl.stderr
+++ b/tests/ui/lint/unused/unused-macro-rules-decl.stderr
@@ -1,4 +1,4 @@
-error: 4th rule of macro `num` is never used
+error: rule #4 of macro `num` is never used
   --> $DIR/unused-macro-rules-decl.rs:11:5
    |
 LL |     (four) => { 4 },
@@ -10,13 +10,13 @@ note: the lint level is defined here
 LL | #![deny(unused_macro_rules)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: 2nd rule of macro `num` is never used
+error: rule #2 of macro `num` is never used
   --> $DIR/unused-macro-rules-decl.rs:9:5
    |
 LL |     (two) => { 2 },
    |     ^^^^^
 
-error: 3rd rule of macro `num_rec` is never used
+error: rule #3 of macro `num_rec` is never used
   --> $DIR/unused-macro-rules-decl.rs:31:5
    |
 LL |     (three) => {
diff --git a/tests/ui/lint/unused/unused-macro-rules.rs b/tests/ui/lint/unused/unused-macro-rules.rs
index eeaf4d1b0a9..39a882e8e4d 100644
--- a/tests/ui/lint/unused/unused-macro-rules.rs
+++ b/tests/ui/lint/unused/unused-macro-rules.rs
@@ -5,9 +5,9 @@
 // Most simple case
 macro_rules! num {
     (one) => { 1 };
-    (two) => { 2 }; //~ ERROR: 2nd rule of macro
+    (two) => { 2 }; //~ ERROR: rule #2 of macro
     (three) => { 3 };
-    (four) => { 4 }; //~ ERROR: 4th rule of macro
+    (four) => { 4 }; //~ ERROR: rule #4 of macro
 }
 const _NUM: u8 = num!(one) + num!(three);
 
@@ -27,7 +27,7 @@ macro_rules! num_rec {
     (two) => {
         num_rec!(one) + num_rec!(one)
     };
-    (three) => { //~ ERROR: 3rd rule of macro
+    (three) => { //~ ERROR: rule #3 of macro
         num_rec!(one) + num_rec!(two)
     };
     (four) => { num_rec!(two) + num_rec!(two) };
diff --git a/tests/ui/lint/unused/unused-macro-rules.stderr b/tests/ui/lint/unused/unused-macro-rules.stderr
index 2b3098a5128..b9258e77805 100644
--- a/tests/ui/lint/unused/unused-macro-rules.stderr
+++ b/tests/ui/lint/unused/unused-macro-rules.stderr
@@ -1,4 +1,4 @@
-error: 4th rule of macro `num` is never used
+error: rule #4 of macro `num` is never used
   --> $DIR/unused-macro-rules.rs:10:5
    |
 LL |     (four) => { 4 };
@@ -10,13 +10,13 @@ note: the lint level is defined here
 LL | #![deny(unused_macro_rules)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: 2nd rule of macro `num` is never used
+error: rule #2 of macro `num` is never used
   --> $DIR/unused-macro-rules.rs:8:5
    |
 LL |     (two) => { 2 };
    |     ^^^^^
 
-error: 3rd rule of macro `num_rec` is never used
+error: rule #3 of macro `num_rec` is never used
   --> $DIR/unused-macro-rules.rs:30:5
    |
 LL |     (three) => {
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
new file mode 100644
index 00000000000..5e880964454
--- /dev/null
+++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
@@ -0,0 +1,32 @@
+error: no rules expected the token `const`
+  --> $DIR/expr_2021_inline_const.rs:21:12
+   |
+LL | macro_rules! m2021 {
+   | ------------------ when calling this macro
+...
+LL |     m2021!(const { 1 });
+   |            ^^^^^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:expr_2021`
+  --> $DIR/expr_2021_inline_const.rs:10:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+
+error: no rules expected the token `const`
+  --> $DIR/expr_2021_inline_const.rs:22:12
+   |
+LL | macro_rules! m2024 {
+   | ------------------ when calling this macro
+...
+LL |     m2024!(const { 1 });
+   |            ^^^^^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:expr`
+  --> $DIR/expr_2021_inline_const.rs:16:6
+   |
+LL |     ($e:expr) => {
+   |      ^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
new file mode 100644
index 00000000000..237ecb2cc19
--- /dev/null
+++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
@@ -0,0 +1,17 @@
+error: no rules expected the token `const`
+  --> $DIR/expr_2021_inline_const.rs:21:12
+   |
+LL | macro_rules! m2021 {
+   | ------------------ when calling this macro
+...
+LL |     m2021!(const { 1 });
+   |            ^^^^^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:expr_2021`
+  --> $DIR/expr_2021_inline_const.rs:10:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
new file mode 100644
index 00000000000..ebc5ea36421
--- /dev/null
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -0,0 +1,23 @@
+//@ revisions: edi2021 edi2024
+//@[edi2024]compile-flags: --edition=2024 -Z unstable-options
+//@[edi2021]compile-flags: --edition=2021
+
+// This test ensures that the inline const match only on edition 2024
+#![feature(expr_fragment_specifier_2024)]
+#![allow(incomplete_features)]
+
+macro_rules! m2021 {
+    ($e:expr_2021) => {
+        $e
+    };
+}
+
+macro_rules! m2024 {
+    ($e:expr) => {
+        $e
+    };
+}
+fn main() {
+    m2021!(const { 1 }); //~ ERROR: no rules expected the token `const`
+    m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const`
+}
diff --git a/tests/ui/macros/expr_2021_old_edition.rs b/tests/ui/macros/expr_2021_old_edition.rs
new file mode 100644
index 00000000000..a7711266106
--- /dev/null
+++ b/tests/ui/macros/expr_2021_old_edition.rs
@@ -0,0 +1,13 @@
+//@  compile-flags: --edition=2018
+
+// This test ensures that expr_2021 is not allowed on pre-2021 editions
+
+macro_rules! m {
+    ($e:expr_2021) => { //~ ERROR: invalid fragment specifier `expr_2021`
+        $e
+    };
+}
+
+fn main() {
+    m!(()); //~ ERROR: no rules expected the token `(`
+}
diff --git a/tests/ui/macros/expr_2021_old_edition.stderr b/tests/ui/macros/expr_2021_old_edition.stderr
new file mode 100644
index 00000000000..bffa8a1ca17
--- /dev/null
+++ b/tests/ui/macros/expr_2021_old_edition.stderr
@@ -0,0 +1,26 @@
+error: invalid fragment specifier `expr_2021`
+  --> $DIR/expr_2021_old_edition.rs:6:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+   |
+   = help: fragment specifier `expr_2021` requires Rust 2021 or later
+           valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: no rules expected the token `(`
+  --> $DIR/expr_2021_old_edition.rs:12:8
+   |
+LL | macro_rules! m {
+   | -------------- when calling this macro
+...
+LL |     m!(());
+   |        ^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:ident`
+  --> $DIR/expr_2021_old_edition.rs:6:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
new file mode 100644
index 00000000000..5a737b29821
--- /dev/null
+++ b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
@@ -0,0 +1,11 @@
+//@  compile-flags: --edition=2024 -Z unstable-options
+
+macro_rules! m {
+    ($e:expr_2021) => { //~ ERROR: fragment specifier `expr_2021` is unstable
+        $e
+    };
+}
+
+fn main() {
+    m!(());
+}
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
new file mode 100644
index 00000000000..273a93877ce
--- /dev/null
+++ b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
@@ -0,0 +1,13 @@
+error[E0658]: fragment specifier `expr_2021` is unstable
+  --> $DIR/feature-gate-expr_fragment_specifier_2024.rs:4:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+   |
+   = note: see issue #123742 <https://github.com/rust-lang/rust/issues/123742> for more information
+   = help: add `#![feature(expr_fragment_specifier_2024)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/macros/issue-98790.rs b/tests/ui/macros/issue-98790.rs
deleted file mode 100644
index b489efe9ce9..00000000000
--- a/tests/ui/macros/issue-98790.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//@ run-pass
-
-macro_rules! stringify_item {
-    ($item:item) => {
-        stringify!($item)
-    };
-}
-
-macro_rules! repro {
-    ($expr:expr) => {
-        stringify_item! {
-            pub fn repro() -> bool {
-                $expr
-            }
-        }
-    };
-}
-
-fn main() {
-    assert_eq!(
-        repro!(match () { () => true } | true),
-        "pub fn repro() -> bool { (match () { () => true, }) | true }"
-    );
-}
diff --git a/tests/ui/macros/missing-semi.rs b/tests/ui/macros/missing-semi.rs
new file mode 100644
index 00000000000..b7e90e9e442
--- /dev/null
+++ b/tests/ui/macros/missing-semi.rs
@@ -0,0 +1,11 @@
+#[allow(unused_macros)]
+macro_rules! foo {
+    () => {
+
+    }
+    () => {
+        //~^ ERROR expected `;`, found `(`
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/missing-semi.stderr b/tests/ui/macros/missing-semi.stderr
new file mode 100644
index 00000000000..0a7afe50059
--- /dev/null
+++ b/tests/ui/macros/missing-semi.stderr
@@ -0,0 +1,8 @@
+error: expected `;`, found `(`
+  --> $DIR/missing-semi.rs:6:5
+   |
+LL |     () => {
+   |     ^ no rules expected this token in macro call
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/macros/println-percent-prefix-num-issue-125002.rs b/tests/ui/macros/println-percent-prefix-num-issue-125002.rs
new file mode 100644
index 00000000000..9f30d48a5cd
--- /dev/null
+++ b/tests/ui/macros/println-percent-prefix-num-issue-125002.rs
@@ -0,0 +1,6 @@
+fn main() {
+    println!("%100000", 1);
+    //~^ ERROR argument never used
+    println!("%     65536", 1);
+    //~^ ERROR argument never used
+}
diff --git a/tests/ui/macros/println-percent-prefix-num-issue-125002.stderr b/tests/ui/macros/println-percent-prefix-num-issue-125002.stderr
new file mode 100644
index 00000000000..7575137be6d
--- /dev/null
+++ b/tests/ui/macros/println-percent-prefix-num-issue-125002.stderr
@@ -0,0 +1,28 @@
+error: argument never used
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:2:25
+   |
+LL |     println!("%100000", 1);
+   |                         ^ argument never used
+   |
+note: format specifiers use curly braces, and the conversion specifier `1` is unknown or unsupported
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:2:15
+   |
+LL |     println!("%100000", 1);
+   |               ^^
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+
+error: argument never used
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:4:29
+   |
+LL |     println!("%     65536", 1);
+   |                             ^ argument never used
+   |
+note: format specifiers use curly braces, and the conversion specifier ` ` is unknown or unsupported
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:4:15
+   |
+LL |     println!("%     65536", 1);
+   |               ^^
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/proc-macro/signature.stderr b/tests/ui/proc-macro/signature.stderr
index 2a53145a643..fd679442b6a 100644
--- a/tests/ui/proc-macro/signature.stderr
+++ b/tests/ui/proc-macro/signature.stderr
@@ -2,7 +2,7 @@ error: derive proc macro has incorrect signature
   --> $DIR/signature.rs:10:1
    |
 LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
    |
    = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
               found signature `unsafe extern "C" fn(i32, u32) -> u32`
diff --git a/tests/ui/traits/impl-method-mismatch.stderr b/tests/ui/traits/impl-method-mismatch.stderr
index 2061fc78575..77d542c729a 100644
--- a/tests/ui/traits/impl-method-mismatch.stderr
+++ b/tests/ui/traits/impl-method-mismatch.stderr
@@ -2,7 +2,7 @@ error[E0053]: method `jumbo` has an incompatible type for trait
   --> $DIR/impl-method-mismatch.rs:7:5
    |
 LL |     unsafe fn jumbo(&self, x: &usize) { *self + *x; }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
    |
 note: type in trait
   --> $DIR/impl-method-mismatch.rs:2:5
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index 044c24fd2b2..170f2c7d34c 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -1,8 +1,8 @@
-error[E0282]: type annotations needed
+error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:10
    |
 LL | struct X<const FN: fn() = { || {} }>;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{ || {} }`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
@@ -23,4 +23,4 @@ LL | struct X<const FN: fn() = { || {} }>;
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
index 6e68646fbe4..57cba790b55 100644
--- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
+++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
@@ -1,12 +1,12 @@
-error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>`
+error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
   --> $DIR/coherence-fulfill-overflow.rs:12:1
    |
 LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
    | ------------------------------------- first implementation here
 LL | impl<T: ?Sized + TwoW> Trait for T {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
    |
-   = note: overflow evaluating the requirement `W<W<W<W<_>>>>: TwoW`
+   = note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>: TwoW`
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
index df25150c21f..8d7d8cee08a 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `_: Sized`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/fixpoint-exponential-growth.rs:33:13
    |
 LL |     impls::<W<_>>();
    |             ^^^^
    |
-note: required for `W<(W<_>, W<_>)>` to implement `Trait`
-  --> $DIR/fixpoint-exponential-growth.rs:23:12
-   |
-LL | impl<T, U> Trait for W<(W<T>, W<U>)>
-   |      -     ^^^^^     ^^^^^^^^^^^^^^^
-   |      |
-   |      unsatisfied trait bound introduced here
 note: required by a bound in `impls`
   --> $DIR/fixpoint-exponential-growth.rs:30:13
    |
diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
index 86c71ad92ff..7cedb4d36c9 100644
--- a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
+++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
@@ -1,53 +1,21 @@
-error[E0275]: overflow evaluating the requirement `(): Inductive`
+error[E0275]: overflow evaluating the requirement `(): Trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:32:19
    |
 LL |     impls_trait::<()>();
    |                   ^^
    |
-note: required for `()` to implement `Trait`
-  --> $DIR/double-cycle-inductive-coinductive.rs:9:34
-   |
-LL | impl<T: Inductive + Coinductive> Trait for T {}
-   |         ---------                ^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `Inductive`
-  --> $DIR/double-cycle-inductive-coinductive.rs:12:16
-   |
-LL | impl<T: Trait> Inductive for T {}
-   |         -----  ^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:17:19
    |
 LL | fn impls_trait<T: Trait>() {}
    |                   ^^^^^ required by this bound in `impls_trait`
 
-error[E0275]: overflow evaluating the requirement `(): CoinductiveRev`
+error[E0275]: overflow evaluating the requirement `(): TraitRev`
   --> $DIR/double-cycle-inductive-coinductive.rs:35:23
    |
 LL |     impls_trait_rev::<()>();
    |                       ^^
    |
-note: required for `()` to implement `TraitRev`
-  --> $DIR/double-cycle-inductive-coinductive.rs:21:40
-   |
-LL | impl<T: CoinductiveRev + InductiveRev> TraitRev for T {}
-   |         --------------                 ^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `CoinductiveRev`
-  --> $DIR/double-cycle-inductive-coinductive.rs:27:19
-   |
-LL | impl<T: TraitRev> CoinductiveRev for T {}
-   |         --------  ^^^^^^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `TraitRev`
 note: required by a bound in `impls_trait_rev`
   --> $DIR/double-cycle-inductive-coinductive.rs:29:23
    |
diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
index ea46c0fea97..a2a5c028cf8 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
@@ -1,19 +1,9 @@
-error[E0275]: overflow evaluating the requirement `W<W<_>>: Trait`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/inductive-fixpoint-hang.rs:31:19
    |
 LL |     impls_trait::<W<_>>();
    |                   ^^^^
    |
-note: required for `W<W<W<_>>>` to implement `Trait`
-  --> $DIR/inductive-fixpoint-hang.rs:22:17
-   |
-LL | impl<T: ?Sized> Trait for W<W<T>>
-   |                 ^^^^^     ^^^^^^^
-LL | where
-LL |     W<T>: Trait,
-   |           ----- unsatisfied trait bound introduced here
-   = note: 8 redundant requirements hidden
-   = note: required for `W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/inductive-fixpoint-hang.rs:28:19
    |
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
index 9d0ea51b1b2..78683372580 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
@@ -39,7 +39,7 @@ fn impls_ar<T: AR>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): B`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 
     impls_ar::<()>();
     //~^ ERROR overflow evaluating the requirement `(): AR`
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
index fe02d3c407c..e9cc6bc6c81 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
@@ -1,25 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): B`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/inductive-not-on-stack.rs:41:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `A`
-  --> $DIR/inductive-not-on-stack.rs:21:16
-   |
-LL | impl<T: B + C> A for T {}
-   |         -      ^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `B`
-  --> $DIR/inductive-not-on-stack.rs:22:12
-   |
-LL | impl<T: A> B for T {}
-   |         -  ^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `A`
 note: required by a bound in `impls_a`
   --> $DIR/inductive-not-on-stack.rs:25:15
    |
@@ -32,29 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): AR`
 LL |     impls_ar::<()>();
    |                ^^
    |
-note: required for `()` to implement `BR`
-  --> $DIR/inductive-not-on-stack.rs:35:13
-   |
-LL | impl<T: AR> BR for T {}
-   |         --  ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `CR`
-  --> $DIR/inductive-not-on-stack.rs:36:13
-   |
-LL | impl<T: BR> CR for T {}
-   |         --  ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `AR`
-  --> $DIR/inductive-not-on-stack.rs:34:18
-   |
-LL | impl<T: CR + BR> AR for T {}
-   |         --       ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 6 redundant requirements hidden
-   = note: required for `()` to implement `AR`
 note: required by a bound in `impls_ar`
   --> $DIR/inductive-not-on-stack.rs:38:16
    |
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
index b90a354be1b..6d75d241864 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
@@ -35,5 +35,5 @@ fn impls_a<T: A>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): CInd`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
index 03e61dbf99c..17544eb1da5 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
@@ -1,46 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): CInd`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/mixed-cycles-1.rs:37:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `B`
-  --> $DIR/mixed-cycles-1.rs:31:28
-   |
-LL | impl<T: ?Sized + CInd + C> B for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `C`
-  --> $DIR/mixed-cycles-1.rs:32:25
-   |
-LL | impl<T: ?Sized + B + A> C for T {}
-   |                  -      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `CInd`
-  --> $DIR/mixed-cycles-1.rs:28:21
-   |
-LL | impl<T: ?Sized + C> CInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-   = note: 4 redundant requirements hidden
-   = note: required for `()` to implement `B`
-note: required for `()` to implement `BInd`
-  --> $DIR/mixed-cycles-1.rs:23:21
-   |
-LL | impl<T: ?Sized + B> BInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `A`
-  --> $DIR/mixed-cycles-1.rs:30:28
-   |
-LL | impl<T: ?Sized + BInd + C> A for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required by a bound in `impls_a`
   --> $DIR/mixed-cycles-1.rs:34:15
    |
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
index a3ffcaafb37..c939a6e5ef2 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
@@ -28,5 +28,5 @@ fn impls_a<T: A>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): BInd`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
index 892426abe82..a9be1016c74 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
@@ -1,32 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): BInd`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/mixed-cycles-2.rs:30:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `B`
-  --> $DIR/mixed-cycles-2.rs:25:24
-   |
-LL | impl<T: ?Sized + BInd> B for T {}
-   |                  ----  ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `BInd`
-  --> $DIR/mixed-cycles-2.rs:22:21
-   |
-LL | impl<T: ?Sized + B> BInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-   = note: 6 redundant requirements hidden
-   = note: required for `()` to implement `BInd`
-note: required for `()` to implement `A`
-  --> $DIR/mixed-cycles-2.rs:24:28
-   |
-LL | impl<T: ?Sized + BInd + B> A for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required by a bound in `impls_a`
   --> $DIR/mixed-cycles-2.rs:27:15
    |
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs
new file mode 100644
index 00000000000..4094ab84166
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+
+trait Trait {
+    type Assoc;
+}
+
+struct W<T>(*mut T);
+impl<T> Trait for W<W<T>>
+where
+    W<T>: Trait,
+{
+    type Assoc = ();
+}
+
+trait NoOverlap {}
+impl<T: Trait> NoOverlap for T {}
+
+impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
+//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr
new file mode 100644
index 00000000000..42be1960563
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
+  --> $DIR/ambiguous-fail.rs:18:1
+   |
+LL | impl<T: Trait> NoOverlap for T {}
+   | ------------------------------ first implementation here
+LL |
+LL | impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs
new file mode 100644
index 00000000000..2d40ba37a89
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+
+trait Trait {
+    type Assoc;
+}
+
+struct W<T>(*mut T);
+impl<T> Trait for W<W<T>>
+where
+    W<T>: Trait,
+{
+    type Assoc = ();
+}
+
+trait NoOverlap {}
+impl<T: Trait> NoOverlap for T {}
+
+impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
+//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr
new file mode 100644
index 00000000000..5c77fc71e55
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
+  --> $DIR/ambiguous-pass.rs:18:1
+   |
+LL | impl<T: Trait> NoOverlap for T {}
+   | ------------------------------ first implementation here
+LL |
+LL | impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs
index 8667b3fe466..9f6dea5d5bf 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.rs
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs
@@ -12,7 +12,7 @@ trait ToUnit<'a> {
 trait Overlap<T> {}
 
 type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;
-//~^ ERROR: not well-formed
+//~^ ERROR the trait bound `*const T: ToUnit<'a>` is not satisfied
 
 impl<T> Overlap<T> for T {}
 
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
index 5cb24fa19aa..2e0566cad08 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
@@ -13,11 +13,17 @@ LL | #![feature(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
 
-error: the type `<*const T as ToUnit<'a>>::Unit` is not well-formed
+error[E0277]: the trait bound `*const T: ToUnit<'a>` is not satisfied
   --> $DIR/issue-118950-root-region.rs:14:21
    |
 LL | type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToUnit<'a>` is not implemented for `*const T`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-118950-root-region.rs:8:1
+   |
+LL | trait ToUnit<'a> {
+   | ^^^^^^^^^^^^^^^^
 
 WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
 WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
@@ -34,5 +40,5 @@ LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0119, E0412.
+Some errors have detailed explanations: E0119, E0277, E0412.
 For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs b/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs
deleted file mode 100644
index a5696fc7796..00000000000
--- a/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ compile-flags: -Znext-solver
-
-trait Trait {
-    type Ty;
-}
-
-impl Trait for for<'a> fn(&'a u8, &'a u8) {
-    type Ty = ();
-}
-
-// argument is necessary to create universes before registering the hidden type.
-fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized {
-    //~^ ERROR the type `<for<'a, 'b> fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed
-    "hidden type is `&'?0 str` with '?0 member of ['static,]"
-}
-
-fn main() {}
diff --git a/tests/ui/traits/next-solver/member-constraints-in-root-universe.stderr b/tests/ui/traits/next-solver/member-constraints-in-root-universe.stderr
deleted file mode 100644
index 7a9982f07f6..00000000000
--- a/tests/ui/traits/next-solver/member-constraints-in-root-universe.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: the type `<for<'a, 'b> fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed
-  --> $DIR/member-constraints-in-root-universe.rs:12:16
-   |
-LL | fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized {
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/next-solver/object-unsafety.rs b/tests/ui/traits/next-solver/object-unsafety.rs
index 3aa1af4956e..a347984daf6 100644
--- a/tests/ui/traits/next-solver/object-unsafety.rs
+++ b/tests/ui/traits/next-solver/object-unsafety.rs
@@ -10,9 +10,8 @@ fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
 
 pub fn copy_any<T>(t: &T) -> T {
     copy::<dyn Setup<From=T>>(t)
-    //~^ ERROR the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
+    //~^ ERROR the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
     //~| ERROR mismatched types
-    //~| ERROR the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
     //~| ERROR the trait bound `T: Copy` is not satisfied
 
     // FIXME(-Znext-solver): These error messages are horrible and some of them
diff --git a/tests/ui/traits/next-solver/object-unsafety.stderr b/tests/ui/traits/next-solver/object-unsafety.stderr
index 7c9a6077fe7..75d0ce24413 100644
--- a/tests/ui/traits/next-solver/object-unsafety.stderr
+++ b/tests/ui/traits/next-solver/object-unsafety.stderr
@@ -15,12 +15,6 @@ help: consider restricting type parameter `T`
 LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
    |                  +++++++++++++++++++
 
-error: the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
-  --> $DIR/object-unsafety.rs:12:31
-   |
-LL |     copy::<dyn Setup<From=T>>(t)
-   |                               ^
-
 error[E0308]: mismatched types
   --> $DIR/object-unsafety.rs:12:31
    |
@@ -37,13 +31,19 @@ note: function defined here
 LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
    |    ^^^^                    --------------
 
-error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
+error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
   --> $DIR/object-unsafety.rs:12:5
    |
 LL |     copy::<dyn Setup<From=T>>(t)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup`
+   |
+   = note: required because it appears within the type `dyn Setup<From = T>`
+help: consider restricting type parameter `T`
+   |
+LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
+   |                  +++++++++++++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
index 052d803765d..186d0e8be56 100644
--- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
+++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
@@ -15,5 +15,5 @@ fn impls<T: Trait>() {}
 
 fn main() {
     impls::<W<_>>();
-    //~^ ERROR overflow evaluating the requirement `_: Sized`
+    //~^ ERROR overflow evaluating the requirement `W<_>: Trait`
 }
diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
index 6583cae8bb9..b032ae3e740 100644
--- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
+++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `_: Sized`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/exponential-trait-goals.rs:17:13
    |
 LL |     impls::<W<_>>();
    |             ^^^^
    |
-note: required for `W<(W<_>, W<_>)>` to implement `Trait`
-  --> $DIR/exponential-trait-goals.rs:7:12
-   |
-LL | impl<T, U> Trait for W<(W<T>, W<U>)>
-   |      -     ^^^^^     ^^^^^^^^^^^^^^^
-   |      |
-   |      unsatisfied trait bound introduced here
 note: required by a bound in `impls`
   --> $DIR/exponential-trait-goals.rs:14:13
    |
diff --git a/tests/ui/traits/next-solver/overflow/global-cache.stderr b/tests/ui/traits/next-solver/overflow/global-cache.stderr
index 9e467721e83..67616619384 100644
--- a/tests/ui/traits/next-solver/overflow/global-cache.stderr
+++ b/tests/ui/traits/next-solver/overflow/global-cache.stderr
@@ -5,15 +5,6 @@ LL |     impls_trait::<Four<Four<Four<Four<()>>>>>();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`)
-note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>` to implement `Trait`
-  --> $DIR/global-cache.rs:12:16
-   |
-LL | impl<T: Trait> Trait for Inc<T> {}
-   |         -----  ^^^^^     ^^^^^^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 5 redundant requirements hidden
-   = note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/global-cache.rs:15:19
    |
diff --git a/tests/ui/unpretty/auxiliary/data.txt b/tests/ui/unpretty/auxiliary/data.txt
new file mode 100644
index 00000000000..2f62e4609f4
--- /dev/null
+++ b/tests/ui/unpretty/auxiliary/data.txt
@@ -0,0 +1 @@
+data for include_bytes in ../expanded-exhaustive.rs
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
new file mode 100644
index 00000000000..6aa032d7ed8
--- /dev/null
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -0,0 +1,888 @@
+//@ compile-flags: -Zunpretty=expanded -Zunstable-options
+//@ edition:2024
+//@ check-pass
+
+#![feature(async_closure)]
+#![feature(auto_traits)]
+#![feature(box_patterns)]
+#![feature(builtin_syntax)]
+#![feature(concat_idents)]
+#![feature(const_trait_impl)]
+#![feature(core_pattern_type)]
+#![feature(decl_macro)]
+#![feature(deref_patterns)]
+#![feature(explicit_tail_calls)]
+#![feature(gen_blocks)]
+#![feature(let_chains)]
+#![feature(more_qualified_paths)]
+#![feature(never_patterns)]
+#![feature(never_type)]
+#![feature(pattern_types)]
+#![feature(prelude_import)]
+#![feature(raw_ref_op)]
+#![feature(specialization)]
+#![feature(trace_macros)]
+#![feature(trait_alias)]
+#![feature(try_blocks)]
+#![feature(unnamed_fields)]
+#![feature(yeet_expr)]
+#![allow(incomplete_features)]
+
+#[prelude_import]
+use self::prelude::*;
+
+mod prelude {
+    pub use std::prelude::rust_2024::*;
+
+    pub type T = _;
+
+    pub trait Trait {
+        const CONST: ();
+    }
+}
+
+mod attributes {
+    //! inner single-line doc comment
+    /*!
+     * inner multi-line doc comment
+     */
+    #![doc = "inner doc attribute"]
+    #![allow(dead_code, unused_variables)]
+    #![no_std]
+
+    /// outer single-line doc comment
+    /**
+     * outer multi-line doc comment
+     */
+    #[doc = "outer doc attribute"]
+    #[doc = concat!("mac", "ro")]
+    #[allow()]
+    #[repr(C)]
+    struct Struct;
+}
+
+mod expressions {
+    /// ExprKind::Array
+    fn expr_array() {
+        [];
+        [true];
+        [true,];
+        [true, true];
+        ["long........................................................................"];
+        ["long............................................................", true];
+    }
+
+    /// ExprKind::ConstBlock
+    fn expr_const_block() {
+        const {};
+        const { 1 };
+        const { struct S; };
+    }
+
+    /// ExprKind::Call
+    fn expr_call() {
+        let f;
+        f();
+        f::<u8>();
+        f::<1>();
+        f::<'static, u8, 1>();
+        f(true);
+        f(true,);
+        ()();
+    }
+
+    /// ExprKind::MethodCall
+    fn expr_method_call() {
+        let x;
+        x.f();
+        x.f::<u8>();
+        x.collect::<Vec<_>>();
+    }
+
+    /// ExprKind::Tup
+    fn expr_tup() {
+        ();
+        (true,);
+        (true, false);
+        (true, false,);
+    }
+
+    /// ExprKind::Binary
+    fn expr_binary() {
+        let (a, b, c, d, x, y);
+        true || false;
+        true || false && false;
+        a < 1 && 2 < b && c > 3 && 4 > d;
+        a & b & !c;
+        a + b * c - d + -1 * -2 - -3;
+        x = !y;
+    }
+
+    /// ExprKind::Unary
+    fn expr_unary() {
+        let expr;
+        *expr;
+        !expr;
+        -expr;
+    }
+
+    /// ExprKind::Lit
+    fn expr_lit() {
+        'x';
+        1_000_i8;
+        1.00000000000000000000001;
+    }
+
+    /// ExprKind::Cast
+    fn expr_cast() {
+        let expr;
+        expr as T;
+        expr as T<u8>;
+    }
+
+    /// ExprKind::Type
+    fn expr_type() {
+        let expr;
+        builtin # type_ascribe(expr, T);
+    }
+
+    /// ExprKind::Let
+    fn expr_let() {
+        let b;
+        if let Some(a) = b {}
+        if let _ = true && false {}
+        if let _ = (true && false) {}
+    }
+
+    /// ExprKind::If
+    fn expr_if() {
+        if true {}
+        if !true {}
+        if let true = true {} else {}
+        if true {} else if false {}
+        if true {} else if false {} else {}
+        if true { return; } else if false { 0 } else { 0 }
+    }
+
+    /// ExprKind::While
+    fn expr_while() {
+        while false {}
+        'a: while false {}
+        while let true = true {}
+    }
+
+    /// ExprKind::ForLoop
+    fn expr_for_loop() {
+        let x;
+        for _ in x {}
+        'a: for _ in x {}
+    }
+
+    /// ExprKind::Loop
+    fn expr_loop() {
+        loop {}
+        'a: loop {}
+    }
+
+    /// ExprKind::Match
+    fn expr_match() {
+        let value;
+        match value {}
+        match value { ok => 1 }
+        match value {
+            ok => 1,
+            err => 0,
+        }
+    }
+
+    /// ExprKind::Closure
+    fn expr_closure() {
+        let value;
+        || {};
+        |x| {};
+        |x: u8| {};
+        || ();
+        move || value;
+        async || value;
+        async move || value;
+        static || value;
+        static move || value;
+        (static async || value);
+        (static async move || value);
+        || -> u8 { value };
+        1 + || {};
+    }
+
+    /// ExprKind::Block
+    fn expr_block() {
+        {}
+        unsafe {}
+        'a: {}
+        #[allow()] {}
+        { #![allow()] }
+    }
+
+    /// ExprKind::Gen
+    fn expr_gen() {
+        async {};
+        async move {};
+        gen {};
+        gen move {};
+        async gen {};
+        async gen move {};
+    }
+
+    /// ExprKind::Await
+    fn expr_await() {
+        let fut;
+        fut.await;
+    }
+
+    /// ExprKind::TryBlock
+    fn expr_try_block() {
+        try {}
+        try { return; }
+    }
+
+    /// ExprKind::Assign
+    fn expr_assign() {
+        let expr;
+        expr = true;
+    }
+
+    /// ExprKind::AssignOp
+    fn expr_assign_op() {
+        let expr;
+        expr += true;
+    }
+
+    /// ExprKind::Field
+    fn expr_field() {
+        let expr;
+        expr.field;
+        expr.0;
+    }
+
+    /// ExprKind::Index
+    fn expr_index() {
+        let expr;
+        expr[true];
+    }
+
+    /// ExprKind::Range
+    fn expr_range() {
+        let (lo, hi);
+        ..;
+        ..hi;
+        lo..;
+        lo..hi;
+        lo .. hi;
+        ..=hi;
+        lo..=hi;
+        -2..=-1;
+    }
+
+    /// ExprKind::Underscore
+    fn expr_underscore() {
+        _;
+    }
+
+    /// ExprKind::Path
+    fn expr_path() {
+        let x;
+        crate::expressions::expr_path;
+        crate::expressions::expr_path::<'static>;
+        <T as Default>::default;
+        <T as ::core::default::Default>::default::<>;
+        x::();
+        x::(T, T) -> T;
+        crate::() -> ()::expressions::() -> ()::expr_path;
+        core::()::marker::()::PhantomData;
+    }
+
+    /// ExprKind::AddrOf
+    fn expr_addr_of() {
+        let expr;
+        &expr;
+        &mut expr;
+        &raw const expr;
+        &raw mut expr;
+    }
+
+    /// ExprKind::Break
+    fn expr_break() {
+        'a: {
+            break;
+            break 'a;
+            break true;
+            break 'a true;
+        }
+    }
+
+    /// ExprKind::Continue
+    fn expr_continue() {
+        'a: {
+            continue;
+            continue 'a;
+        }
+    }
+
+    /// ExprKind::Ret
+    fn expr_ret() {
+        return;
+        return true;
+    }
+
+    /// ExprKind::InlineAsm
+    fn expr_inline_asm() {
+        let x;
+        core::arch::asm!(
+            "mov {tmp}, {x}",
+            "shl {tmp}, 1",
+            "shl {x}, 2",
+            "add {x}, {tmp}",
+            x = inout(reg) x,
+            tmp = out(reg) _,
+        );
+    }
+
+    /// ExprKind::OffsetOf
+    fn expr_offset_of() {
+        core::mem::offset_of!(T, field);
+    }
+
+    /// ExprKind::MacCall
+    fn expr_mac_call() {
+        stringify!(...);
+        stringify![...];
+        stringify! { ... };
+    }
+
+    /// ExprKind::Struct
+    fn expr_struct() {
+        struct Struct {}
+        let (x, base);
+        Struct {};
+        <Struct as ToOwned>::Owned {};
+        Struct { .. };
+        Struct { .. base };
+        Struct { x };
+        Struct { x, ..base };
+        Struct { x: true };
+        Struct { x: true, .. };
+        Struct { x: true, ..base };
+        Struct { 0: true, ..base };
+    }
+
+    /// ExprKind::Repeat
+    fn expr_repeat() {
+        [(); 0];
+    }
+
+    /// ExprKind::Paren
+    fn expr_paren() {
+        let expr;
+        (expr);
+    }
+
+    /// ExprKind::Try
+    fn expr_try() {
+        let expr;
+        expr?;
+    }
+
+    /// ExprKind::Yield
+    fn expr_yield() {
+        yield;
+        yield true;
+    }
+
+    /// ExprKind::Yeet
+    fn expr_yeet() {
+        do yeet;
+        do yeet 0;
+    }
+
+    /// ExprKind::Become
+    fn expr_become() {
+        become true;
+    }
+
+    /// ExprKind::IncludedBytes
+    fn expr_include_bytes() {
+        include_bytes!("auxiliary/data.txt");
+    }
+
+    /// ExprKind::FormatArgs
+    fn expr_format_args() {
+        let expr;
+        format_args!("");
+        format_args!("{}", expr);
+    }
+}
+
+mod items {
+    /// ItemKind::ExternCrate
+    mod item_extern_crate {
+        extern crate core;
+        extern crate self as unpretty;
+        pub extern crate core as _;
+    }
+
+    /// ItemKind::Use
+    mod item_use {
+        use crate::{expressions, items::item_use};
+        pub use core::*;
+    }
+
+    /// ItemKind::Static
+    mod item_static {
+        pub static A: () = {};
+        static mut B: () = {};
+    }
+
+    /// ItemKind::Const
+    mod item_const {
+        pub const A: () = {};
+
+        trait TraitItems {
+            const B: ();
+            const C: () = {};
+        }
+    }
+
+    /// ItemKind::Fn
+    mod item_fn {
+        pub const unsafe extern "C" fn f() {}
+        pub async unsafe extern fn g() {}
+        fn h<'a, T>() where T: 'a {}
+
+        trait TraitItems {
+            unsafe extern fn f();
+        }
+
+        impl TraitItems for _ {
+            default unsafe extern fn f() {}
+        }
+    }
+
+    /// ItemKind::Mod
+    mod item_mod {
+        // ...
+    }
+
+    /// ItemKind::ForeignMod
+    mod item_foreign_mod {
+        extern "C++" {}
+        extern {}
+    }
+
+    /// ItemKind::GlobalAsm
+    mod item_global_asm {
+        core::arch::global_asm!(".globl my_asm_func");
+    }
+
+    /// ItemKind::TyAlias
+    mod item_ty_alias {
+        pub type Type<'a> where T: 'a, = T;
+    }
+
+    /// ItemKind::Enum
+    mod item_enum {
+        pub enum Void {}
+        enum Empty {
+            Unit,
+            Tuple(),
+            Struct {},
+        }
+        enum Generic<'a, T>
+        where
+            T: 'a,
+        {
+            Tuple(T),
+            Struct { t: T },
+        }
+    }
+
+    /// ItemKind::Struct
+    mod item_struct {
+        pub struct Unit;
+        struct Tuple();
+        struct Newtype(Unit);
+        struct Struct {}
+        struct Generic<'a, T>
+        where
+            T: 'a,
+        {
+            t: T,
+        }
+    }
+
+    /// ItemKind::Union
+    mod item_union {
+        union Generic<'a, T>
+        where
+            T: 'a,
+        {
+            t: T,
+        }
+    }
+
+    /// ItemKind::Trait
+    mod item_trait {
+        pub unsafe auto trait Send {}
+        trait Trait<'a>: Sized
+        where
+            Self: 'a,
+        {
+        }
+    }
+
+    /// ItemKind::TraitAlias
+    mod item_trait_alias {
+        pub trait Trait<T> = Sized where for<'a> T: 'a;
+    }
+
+    /// ItemKind::Impl
+    mod item_impl {
+        impl () {}
+        impl<T> () {}
+        impl Default for () {}
+        impl<T> const Default for () {}
+    }
+
+    /// ItemKind::MacCall
+    mod item_mac_call {
+        trace_macros!(false);
+        trace_macros![false];
+        trace_macros! { false }
+    }
+
+    /// ItemKind::MacroDef
+    mod item_macro_def {
+        macro_rules! mac { () => {...}; }
+        pub macro stringify() {}
+    }
+
+    /// ItemKind::Delegation
+    mod item_delegation {
+        /*! FIXME: todo */
+    }
+
+    /// ItemKind::DelegationMac
+    mod item_delegation_mac {
+        /*! FIXME: todo */
+    }
+}
+
+mod patterns {
+    /// PatKind::Wild
+    fn pat_wild() {
+        let _;
+    }
+
+    /// PatKind::Ident
+    fn pat_ident() {
+        let x;
+        let ref x;
+        let mut x;
+        let ref mut x;
+        let ref mut x @ _;
+    }
+
+    /// PatKind::Struct
+    fn pat_struct() {
+        let T {};
+        let T::<T> {};
+        let T::<'static> {};
+        let T { x };
+        let T { x: _x };
+        let T { .. };
+        let T { x, .. };
+        let T { x: _x, .. };
+        let T { 0: _x, .. };
+        let <T as ToOwned>::Owned {};
+    }
+
+    /// PatKind::TupleStruct
+    fn pat_tuple_struct() {
+        struct Tuple();
+        let Tuple();
+        let Tuple::<T>();
+        let Tuple::<'static>();
+        let Tuple(x);
+        let Tuple(..);
+        let Tuple(x, ..);
+    }
+
+    /// PatKind::Or
+    fn pat_or() {
+        let (true | false);
+        let (| true);
+        let (|true| false);
+    }
+
+    /// PatKind::Path
+    fn pat_path() {
+        let core::marker::PhantomData;
+        let core::marker::PhantomData::<T>;
+        let core::marker::PhantomData::<'static>;
+        let <T as Trait>::CONST;
+    }
+
+    /// PatKind::Tuple
+    fn pat_tuple() {
+        let ();
+        let (true,);
+        let (true, false);
+    }
+
+    /// PatKind::Box
+    fn pat_box() {
+        let box pat;
+    }
+
+    /// PatKind::Deref
+    fn pat_deref() {
+        let deref!(pat);
+    }
+
+    /// PatKind::Ref
+    fn pat_ref() {
+        let &pat;
+        let &mut pat;
+    }
+
+    /// PatKind::Lit
+    fn pat_lit() {
+        let 1_000_i8;
+        let -"";
+    }
+
+    /// PatKind::Range
+    fn pat_range() {
+        let ..1;
+        let 0..;
+        let 0..1;
+        let 0..=1;
+        let -2..=-1;
+    }
+
+    /// PatKind::Slice
+    fn pat_slice() {
+        let [];
+        let [true];
+        let [true,];
+        let [true, false];
+    }
+
+    /// PatKind::Rest
+    fn pat_rest() {
+        let ..;
+    }
+
+    /// PatKind::Never
+    fn pat_never() {
+        let !;
+        let Some(!);
+    }
+
+    /// PatKind::Paren
+    fn pat_paren() {
+        let (pat);
+    }
+
+    /// PatKind::MacCall
+    fn pat_mac_call() {
+        let stringify!();
+        let stringify![];
+        let stringify! {};
+    }
+}
+
+mod statements {
+    /// StmtKind::Let
+    fn stmt_let() {
+        let _;
+        let _ = true;
+        let _: T = true;
+        let _ = true else { return; };
+    }
+
+    /// StmtKind::Item
+    fn stmt_item() {
+        struct Struct {}
+        struct Unit;
+    }
+
+    /// StmtKind::Expr
+    fn stmt_expr() {
+        ()
+    }
+
+    /// StmtKind::Semi
+    fn stmt_semi() {
+        1 + 1;
+    }
+
+    /// StmtKind::Empty
+    fn stmt_empty() {
+        ;
+    }
+
+    /// StmtKind::MacCall
+    fn stmt_mac_call() {
+        stringify!(...);
+        stringify![...];
+        stringify! { ... };
+    }
+}
+
+mod types {
+    /// TyKind::Slice
+    fn ty_slice() {
+        let _: [T];
+    }
+
+    /// TyKind::Array
+    fn ty_array() {
+        let _: [T; 0];
+    }
+
+    /// TyKind::Ptr
+    fn ty_ptr() {
+        let _: *const T;
+        let _: *mut T;
+    }
+
+    /// TyKind::Ref
+    fn ty_ref() {
+        let _: &T;
+        let _: &mut T;
+        let _: &'static T;
+        let _: &'static mut [T];
+        let _: &T<T<T<T<T>>>>;
+        let _: &T<T<T<T<T> > > >;
+    }
+
+    /// TyKind::BareFn
+    fn ty_bare_fn() {
+        let _: fn();
+        let _: fn() -> ();
+        let _: fn(T);
+        let _: fn(t: T);
+        let _: for<> fn();
+        let _: for<'a> fn();
+    }
+
+    /// TyKind::Never
+    fn ty_never() {
+        let _: !;
+    }
+
+    /// TyKind::Tup
+    fn ty_tup() {
+        let _: ();
+        let _: (T,);
+        let _: (T, T);
+    }
+
+    /// TyKind::AnonStruct
+    fn ty_anon_struct() {
+        struct Struct {
+            _: struct { t: T },
+        }
+    }
+
+    /// TyKind::AnonUnion
+    fn ty_anon_union() {
+        struct Struct {
+            _: union { t: T },
+        }
+    }
+
+    /// TyKind::Path
+    fn ty_path() {
+        let _: T;
+        let _: T<'static>;
+        let _: T<T>;
+        let _: T::<T>;
+        let _: T() -> !;
+        let _: <T as ToOwned>::Owned;
+    }
+
+    /// TyKind::TraitObject
+    fn ty_trait_object() {
+        let _: dyn Send;
+        let _: dyn Send + 'static;
+        let _: dyn 'static + Send;
+        let _: dyn for<'a> Send;
+    }
+
+    /// TyKind::ImplTrait
+    const fn ty_impl_trait() {
+        let _: impl Send;
+        let _: impl Send + 'static;
+        let _: impl 'static + Send;
+        let _: impl ?Sized;
+        let _: impl ~const Clone;
+        let _: impl for<'a> Send;
+    }
+
+    /// TyKind::Paren
+    fn ty_paren() {
+        let _: (T);
+    }
+
+    /// TyKind::Typeof
+    fn ty_typeof() {
+        /*! unused for now */
+    }
+
+    /// TyKind::Infer
+    fn ty_infer() {
+        let _: _;
+    }
+
+    /// TyKind::ImplicitSelf
+    fn ty_implicit_self() {
+        /*! there is no syntax for this */
+    }
+
+    /// TyKind::MacCall
+    fn ty_mac_call() {
+        let _: concat_idents!(T);
+        let _: concat_idents![T];
+        let _: concat_idents! { T };
+    }
+
+    /// TyKind::CVarArgs
+    fn ty_c_var_args() {
+        /*! FIXME: todo */
+    }
+
+    /// TyKind::Pat
+    fn ty_pat() {
+        let _: core::pattern_type!(u32 is 1..);
+    }
+}
+
+mod visibilities {
+    /// VisibilityKind::Public
+    mod visibility_public {
+        pub struct Pub;
+    }
+
+    /// VisibilityKind::Restricted
+    mod visibility_restricted {
+        pub(crate) struct PubCrate;
+        pub(self) struct PubSelf;
+        pub(super) struct PubSuper;
+        pub(in crate) struct PubInCrate;
+        pub(in self) struct PubInSelf;
+        pub(in super) struct PubInSuper;
+        pub(in crate::visibilities) struct PubInCrateVisibilities;
+        pub(in self::super) struct PubInSelfSuper;
+        pub(in super::visibility_restricted) struct PubInSuperMod;
+    }
+}
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
new file mode 100644
index 00000000000..325bace7b56
--- /dev/null
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -0,0 +1,719 @@
+#![feature(prelude_import)]
+//@ compile-flags: -Zunpretty=expanded -Zunstable-options
+//@ edition:2024
+//@ check-pass
+
+#![feature(async_closure)]
+#![feature(auto_traits)]
+#![feature(box_patterns)]
+#![feature(builtin_syntax)]
+#![feature(concat_idents)]
+#![feature(const_trait_impl)]
+#![feature(core_pattern_type)]
+#![feature(decl_macro)]
+#![feature(deref_patterns)]
+#![feature(explicit_tail_calls)]
+#![feature(gen_blocks)]
+#![feature(let_chains)]
+#![feature(more_qualified_paths)]
+#![feature(never_patterns)]
+#![feature(never_type)]
+#![feature(pattern_types)]
+#![feature(prelude_import)]
+#![feature(raw_ref_op)]
+#![feature(specialization)]
+#![feature(trace_macros)]
+#![feature(trait_alias)]
+#![feature(try_blocks)]
+#![feature(unnamed_fields)]
+#![feature(yeet_expr)]
+#![allow(incomplete_features)]
+#[prelude_import]
+use std::prelude::rust_2024::*;
+#[macro_use]
+extern crate std;
+
+#[prelude_import]
+use self::prelude::*;
+
+mod prelude {
+    pub use std::prelude::rust_2024::*;
+
+    pub type T = _;
+
+    pub trait Trait {
+        const CONST: ();
+    }
+}
+
+mod attributes {
+    //! inner single-line doc comment
+    /*!
+     * inner multi-line doc comment
+     */
+    #![doc = "inner doc attribute"]
+    #![allow(dead_code, unused_variables)]
+    #![no_std]
+
+    /// outer single-line doc comment
+    /**
+     * outer multi-line doc comment
+     */
+    #[doc = "outer doc attribute"]
+    #[doc = "macro"]
+    #[allow()]
+    #[repr(C)]
+    struct Struct;
+}
+
+mod expressions {
+    /// ExprKind::Array
+    fn expr_array() {
+        [];
+        [true];
+        [true];
+        [true, true];
+        ["long........................................................................"];
+        ["long............................................................",
+                true];
+    }
+
+    /// ExprKind::ConstBlock
+    fn expr_const_block() {
+        const {};
+        const { 1 };
+        const {
+                struct S;
+            };
+    }
+
+    /// ExprKind::Call
+    fn expr_call() {
+        let f;
+        f();
+        f::<u8>();
+        f::<1>();
+        f::<'static, u8, 1>();
+        f(true);
+        f(true);
+        ()();
+    }
+
+    /// ExprKind::MethodCall
+    fn expr_method_call() {
+        let x;
+        x.f();
+        x.f::<u8>();
+        x.collect::<Vec<_>>();
+    }
+
+    /// ExprKind::Tup
+    fn expr_tup() { (); (true,); (true, false); (true, false); }
+
+    /// ExprKind::Binary
+    fn expr_binary() {
+        let (a, b, c, d, x, y);
+        true || false;
+        true || false && false;
+        a < 1 && 2 < b && c > 3 && 4 > d;
+        a & b & !c;
+        a + b * c - d + -1 * -2 - -3;
+        x = !y;
+    }
+
+    /// ExprKind::Unary
+    fn expr_unary() { let expr; *expr; !expr; -expr; }
+
+    /// ExprKind::Lit
+    fn expr_lit() { 'x'; 1_000_i8; 1.00000000000000000000001; }
+
+    /// ExprKind::Cast
+    fn expr_cast() { let expr; expr as T; expr as T<u8>; }
+
+    /// ExprKind::Type
+    fn expr_type() { let expr; builtin # type_ascribe(expr, T); }
+
+    /// ExprKind::Let
+    fn expr_let() {
+        let b;
+        if let Some(a) = b {}
+        if let _ = true && false {}
+        if let _ = (true && false) {}
+    }
+
+    /// ExprKind::If
+    fn expr_if() {
+        if true {}
+        if !true {}
+        if let true = true {} else {}
+        if true {} else if false {}
+        if true {} else if false {} else {}
+        if true { return; } else if false { 0 } else { 0 }
+    }
+
+    /// ExprKind::While
+    fn expr_while() {
+        while false {}
+        'a: while false {}
+        while let true = true {}
+    }
+
+    /// ExprKind::ForLoop
+    fn expr_for_loop() { let x; for _ in x {} 'a: for _ in x {} }
+
+    /// ExprKind::Loop
+    fn expr_loop() { loop {} 'a: loop {} }
+
+    /// ExprKind::Match
+    fn expr_match() {
+        let value;
+        match value {}
+        match value { ok => 1, }
+        match value { ok => 1, err => 0, }
+    }
+
+    /// ExprKind::Closure
+    fn expr_closure() {
+        let value;
+        || {};
+        |x| {};
+        |x: u8| {};
+        || ();
+        move || value;
+        async || value;
+        async move || value;
+        static || value;
+        static move || value;
+        (static async || value);
+        (static async move || value);
+        || -> u8 { value };
+        1 + (|| {});
+    }
+
+    /// ExprKind::Block
+    fn expr_block() {
+        {}
+        unsafe {}
+        'a: {}
+
+        #[allow()]
+        {}
+        {
+            #![allow()]
+        }
+    }
+
+    /// ExprKind::Gen
+    fn expr_gen() {
+        async {};
+        async move {};
+        gen {};
+        gen move {};
+        async gen {};
+        async gen move {};
+    }
+
+    /// ExprKind::Await
+    fn expr_await() { let fut; fut.await; }
+
+    /// ExprKind::TryBlock
+    fn expr_try_block() { try {} try { return; } }
+
+    /// ExprKind::Assign
+    fn expr_assign() { let expr; expr = true; }
+
+    /// ExprKind::AssignOp
+    fn expr_assign_op() { let expr; expr += true; }
+
+    /// ExprKind::Field
+    fn expr_field() { let expr; expr.field; expr.0; }
+
+    /// ExprKind::Index
+    fn expr_index() { let expr; expr[true]; }
+
+    /// ExprKind::Range
+    fn expr_range() {
+        let (lo, hi);
+        ..;
+        ..hi;
+        lo..;
+        lo..hi;
+        lo..hi;
+        ..=hi;
+        lo..=hi;
+        -2..=-1;
+    }
+
+    /// ExprKind::Underscore
+    fn expr_underscore() { _; }
+
+    /// ExprKind::Path
+    fn expr_path() {
+        let x;
+        crate::expressions::expr_path;
+        crate::expressions::expr_path::<'static>;
+        <T as Default>::default;
+        <T as ::core::default::Default>::default::<>;
+        x::();
+        x::(T, T) -> T;
+        crate::() -> ()::expressions::() -> ()::expr_path;
+        core::()::marker::()::PhantomData;
+    }
+
+    /// ExprKind::AddrOf
+    fn expr_addr_of() {
+        let expr;
+        &expr;
+        &mut expr;
+        &raw const expr;
+        &raw mut expr;
+    }
+
+    /// ExprKind::Break
+    fn expr_break() { 'a: { break; break 'a; break true; break 'a true; } }
+
+    /// ExprKind::Continue
+    fn expr_continue() { 'a: { continue; continue 'a; } }
+
+    /// ExprKind::Ret
+    fn expr_ret() { return; return true; }
+
+    /// ExprKind::InlineAsm
+    fn expr_inline_asm() {
+        let x;
+        asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}",
+            inout(reg)
+            x,
+            out(reg)
+            _);
+    }
+
+    /// ExprKind::OffsetOf
+    fn expr_offset_of() {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        // ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        { builtin # offset_of(T, field) };
+    }
+    /// ExprKind::MacCall
+    fn expr_mac_call() { "..."; "..."; "..."; }
+    /// ExprKind::Struct
+    fn expr_struct() {
+        struct Struct {}
+        let (x, base);
+        Struct {};
+        <Struct as ToOwned>::Owned {};
+        Struct { .. };
+        Struct { ..base };
+        Struct { x };
+        Struct { x, ..base };
+        Struct { x: true };
+        Struct { x: true, .. };
+        Struct { x: true, ..base };
+        Struct { 0: true, ..base };
+    }
+    /// ExprKind::Repeat
+    fn expr_repeat() { [(); 0]; }
+    /// ExprKind::Paren
+    fn expr_paren() { let expr; (expr); }
+    /// ExprKind::Try
+    fn expr_try() { let expr; expr?; }
+    /// ExprKind::Yield
+    fn expr_yield() { yield; yield true; }
+    /// ExprKind::Yeet
+    fn expr_yeet() { do yeet; do yeet 0; }
+    /// ExprKind::Become
+    fn expr_become() { become true; }
+    /// ExprKind::IncludedBytes
+    fn expr_include_bytes() {
+        b"data for include_bytes in ../expanded-exhaustive.rs\n";
+    }
+    /// ExprKind::FormatArgs
+    fn expr_format_args() {
+        let expr;
+        format_args!("");
+        format_args!("{0}", expr);
+    }
+}
+mod items {
+    /// ItemKind::ExternCrate
+    mod item_extern_crate {
+        extern crate core;
+        extern crate self as unpretty;
+        pub extern crate core as _;
+    }
+    /// ItemKind::Use
+    mod item_use {
+        use crate::{expressions, items::item_use};
+        pub use core::*;
+    }
+    /// ItemKind::Static
+    mod item_static {
+        pub static A: () = {};
+        static mut B: () = {};
+    }
+    /// ItemKind::Const
+    mod item_const {
+        pub const A: () = {};
+        trait TraitItems {
+            const B: ();
+            const C: () = {};
+        }
+    }
+    /// ItemKind::Fn
+    mod item_fn {
+        pub const unsafe extern "C" fn f() {}
+        pub async unsafe extern fn g() {}
+        fn h<'a, T>() where T: 'a {}
+        trait TraitItems {
+            unsafe extern fn f();
+        }
+        impl TraitItems for _ {
+            default unsafe extern fn f() {}
+        }
+    }
+    /// ItemKind::Mod
+    mod item_mod { }
+    /// ItemKind::ForeignMod
+    mod item_foreign_mod {
+        extern "C++" {}
+        extern {}
+    }
+    /// ItemKind::GlobalAsm
+    mod item_global_asm {
+        global_asm! (".globl my_asm_func");
+    }
+    /// ItemKind::TyAlias
+    mod item_ty_alias {
+        pub type Type<'a> where T: 'a = T;
+    }
+    /// ItemKind::Enum
+    mod item_enum {
+        pub enum Void {}
+        enum Empty { Unit, Tuple(), Struct {}, }
+        enum Generic<'a, T> where T: 'a {
+            Tuple(T),
+            Struct {
+                t: T,
+            },
+        }
+    }
+    /// ItemKind::Struct
+    mod item_struct {
+        pub struct Unit;
+        struct Tuple();
+        struct Newtype(Unit);
+        struct Struct {}
+        struct Generic<'a, T> where T: 'a {
+            t: T,
+        }
+    }
+    /// ItemKind::Union
+    mod item_union {
+        union Generic<'a, T> where T: 'a {
+            t: T,
+        }
+    }
+    /// ItemKind::Trait
+    mod item_trait {
+        pub unsafe auto trait Send {}
+        trait Trait<'a>: Sized where Self: 'a {}
+    }
+    /// ItemKind::TraitAlias
+    mod item_trait_alias {
+        pub trait Trait<T> = Sized where for<'a> T: 'a;
+    }
+    /// ItemKind::Impl
+    mod item_impl {
+        impl () {}
+        impl<T> () {}
+        impl Default for () {}
+        impl<T> const Default for () {}
+    }
+    /// ItemKind::MacCall
+    mod item_mac_call { }
+    /// ItemKind::MacroDef
+    mod item_macro_def {
+        macro_rules! mac { () => { ... }; }
+        pub macro stringify { () => {} }
+    }
+    /// ItemKind::Delegation
+    mod item_delegation {
+        /*! FIXME: todo */
+    }
+    /// ItemKind::DelegationMac
+    mod item_delegation_mac {
+        /*! FIXME: todo */
+    }
+}
+mod patterns {
+    /// PatKind::Wild
+    fn pat_wild() { let _; }
+    /// PatKind::Ident
+    fn pat_ident() {
+        let x;
+        let ref x;
+        let mut x;
+        let ref mut x;
+        let ref mut x @ _;
+    }
+    /// PatKind::Struct
+    fn pat_struct() {
+        let T {};
+        let T::<T> {};
+        let T::<'static> {};
+        let T { x };
+        let T { x: _x };
+        let T { .. };
+        let T { x, .. };
+        let T { x: _x, .. };
+        let T { 0: _x, .. };
+        let <T as ToOwned>::Owned {};
+    }
+    /// PatKind::TupleStruct
+    fn pat_tuple_struct() {
+        struct Tuple();
+        let Tuple();
+        let Tuple::<T>();
+        let Tuple::<'static>();
+        let Tuple(x);
+        let Tuple(..);
+        let Tuple(x, ..);
+    }
+    /// PatKind::Or
+    fn pat_or() { let (true | false); let (true); let (true | false); }
+    /// PatKind::Path
+    fn pat_path() {
+        let core::marker::PhantomData;
+        let core::marker::PhantomData::<T>;
+        let core::marker::PhantomData::<'static>;
+        let <T as Trait>::CONST;
+    }
+    /// PatKind::Tuple
+    fn pat_tuple() { let (); let (true,); let (true, false); }
+    /// PatKind::Box
+    fn pat_box() { let box pat; }
+    /// PatKind::Deref
+    fn pat_deref() { let deref!(pat); }
+    /// PatKind::Ref
+    fn pat_ref() { let &pat; let &mut pat; }
+    /// PatKind::Lit
+    fn pat_lit() { let 1_000_i8; let -""; }
+    /// PatKind::Range
+    fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; }
+    /// PatKind::Slice
+    fn pat_slice() { let []; let [true]; let [true]; let [true, false]; }
+    /// PatKind::Rest
+    fn pat_rest() { let ..; }
+    /// PatKind::Never
+    fn pat_never() { let !; let Some(!); }
+    /// PatKind::Paren
+    fn pat_paren() { let (pat); }
+    /// PatKind::MacCall
+    fn pat_mac_call() { let ""; let ""; let ""; }
+}
+mod statements {
+    /// StmtKind::Let
+    fn stmt_let() {
+        let _;
+        let _ = true;
+        let _: T = true;
+        let _ = true else { return; };
+    }
+    /// StmtKind::Item
+    fn stmt_item() {
+        struct Struct {}
+        struct Unit;
+    }
+    /// StmtKind::Expr
+    fn stmt_expr() { () }
+    /// StmtKind::Semi
+    fn stmt_semi() { 1 + 1; }
+    /// StmtKind::Empty
+    fn stmt_empty() { ; }
+    /// StmtKind::MacCall
+    fn stmt_mac_call() { "..."; "..."; "..."; }
+}
+mod types {
+    /// TyKind::Slice
+    fn ty_slice() { let _: [T]; }
+    /// TyKind::Array
+    fn ty_array() { let _: [T; 0]; }
+    /// TyKind::Ptr
+    fn ty_ptr() { let _: *const T; let _: *mut T; }
+    /// TyKind::Ref
+    fn ty_ref() {
+        let _: &T;
+        let _: &mut T;
+        let _: &'static T;
+        let _: &'static mut [T];
+        let _: &T<T<T<T<T>>>>;
+        let _: &T<T<T<T<T>>>>;
+    }
+    /// TyKind::BareFn
+    fn ty_bare_fn() {
+        let _: fn();
+        let _: fn() -> ();
+        let _: fn(T);
+        let _: fn(t: T);
+        let _: fn();
+        let _: for<'a> fn();
+    }
+    /// TyKind::Never
+    fn ty_never() { let _: !; }
+    /// TyKind::Tup
+    fn ty_tup() { let _: (); let _: (T,); let _: (T, T); }
+    /// TyKind::AnonStruct
+    fn ty_anon_struct() {
+        struct Struct {
+            _: struct  {
+                t: T,
+            },
+        }
+    }
+    /// TyKind::AnonUnion
+    fn ty_anon_union() {
+        struct Struct {
+            _: union  {
+                t: T,
+            },
+        }
+    }
+    /// TyKind::Path
+    fn ty_path() {
+        let _: T;
+        let _: T<'static>;
+        let _: T<T>;
+        let _: T<T>;
+        let _: T() -> !;
+        let _: <T as ToOwned>::Owned;
+    }
+    /// TyKind::TraitObject
+    fn ty_trait_object() {
+        let _: dyn Send;
+        let _: dyn Send + 'static;
+        let _: dyn 'static + Send;
+        let _: dyn for<'a> Send;
+    }
+    /// TyKind::ImplTrait
+    const fn ty_impl_trait() {
+        let _: impl Send;
+        let _: impl Send + 'static;
+        let _: impl 'static + Send;
+        let _: impl ?Sized;
+        let _: impl ~const Clone;
+        let _: impl for<'a> Send;
+    }
+    /// TyKind::Paren
+    fn ty_paren() { let _: (T); }
+    /// TyKind::Typeof
+    fn ty_typeof() {
+        /*! unused for now */
+    }
+    /// TyKind::Infer
+    fn ty_infer() { let _: _; }
+    /// TyKind::ImplicitSelf
+    fn ty_implicit_self() {
+        /*! there is no syntax for this */
+    }
+    /// TyKind::MacCall
+    fn ty_mac_call() { let _: T; let _: T; let _: T; }
+    /// TyKind::CVarArgs
+    fn ty_c_var_args() {
+        /*! FIXME: todo */
+    }
+    /// TyKind::Pat
+    fn ty_pat() { let _: u32 is 1..; }
+}
+mod visibilities {
+    /// VisibilityKind::Public
+    mod visibility_public {
+        pub struct Pub;
+    }
+    /// VisibilityKind::Restricted
+    mod visibility_restricted {
+        pub(crate) struct PubCrate;
+        pub(self) struct PubSelf;
+        pub(super) struct PubSuper;
+        pub(in crate) struct PubInCrate;
+        pub(in self) struct PubInSelf;
+        pub(in super) struct PubInSuper;
+        pub(in crate::visibilities) struct PubInCrateVisibilities;
+        pub(in self::super) struct PubInSelfSuper;
+        pub(in super::visibility_restricted) struct PubInSuperMod;
+    }
+}
diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs
new file mode 100644
index 00000000000..8f0e21ce870
--- /dev/null
+++ b/tests/ui/unpretty/expanded-interpolation.rs
@@ -0,0 +1,106 @@
+//@ compile-flags: -Zunpretty=expanded
+//@ check-pass
+
+// This test covers the AST pretty-printer's insertion of parentheses in some
+// macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in
+// the syntax tree) need to be printed in order for the printed code to be valid
+// Rust syntax. We also test negative cases: the pretty-printer should not be
+// synthesizing parentheses indiscriminately; only where necessary.
+
+#![feature(let_chains)]
+#![feature(if_let_guard)]
+
+macro_rules! expr {
+    ($expr:expr) => { $expr };
+}
+
+macro_rules! stmt {
+    ($stmt:stmt) => { $stmt };
+}
+
+fn if_let() {
+    macro_rules! if_let {
+        ($pat:pat, $expr:expr) => {
+            if let $pat = $expr {}
+        };
+    }
+
+    if let no_paren = true && false {}
+    if_let!(paren_around_binary, true && false);
+    if_let!(no_paren, true);
+
+    struct Struct {}
+    match () {
+        _ if let no_paren = Struct {} => {}
+    }
+}
+
+fn let_else() {
+    let no_paren = expr!(1 + 1) else { return; };
+    let paren_around_loop = expr!(loop {}) else { return; };
+}
+
+fn local() {
+    macro_rules! let_expr_minus_one {
+        ($pat:pat, $expr:expr) => {
+            let $pat = $expr - 1;
+        };
+    }
+
+    let void;
+    let_expr_minus_one!(no_paren, match void {});
+
+    macro_rules! let_expr_else_return {
+        ($pat:pat, $expr:expr) => {
+            let $pat = $expr else { return; };
+        };
+    }
+
+    let_expr_else_return!(no_paren, void());
+}
+
+fn match_arm() {
+    macro_rules! match_arm {
+        ($pat:pat, $expr:expr) => {
+            match () { $pat => $expr }
+        };
+    }
+
+    match_arm!(no_paren, 1 - 1);
+    match_arm!(paren_around_brace, { 1 } - 1);
+}
+
+/// https://github.com/rust-lang/rust/issues/98790
+fn stmt_boundary() {
+    macro_rules! expr_as_stmt {
+        ($expr:expr) => {
+            stmt!($expr)
+        };
+    }
+
+    let paren_around_match;
+    expr_as_stmt!(match paren_around_match {} | true);
+
+    macro_rules! minus_one {
+        ($expr:expr) => {
+            expr_as_stmt!($expr - 1)
+        };
+    }
+
+    let (no_paren, paren_around_loop);
+    minus_one!(no_paren);
+    minus_one!(match paren_around_match {});
+    minus_one!(match paren_around_match {}());
+    minus_one!(match paren_around_match {}[0]);
+    minus_one!(loop { break paren_around_loop; });
+}
+
+fn vis_inherited() {
+    macro_rules! vis_inherited {
+        ($vis:vis struct) => {
+            $vis struct Struct;
+        };
+    }
+
+    vis_inherited!(struct);
+}
diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout
new file mode 100644
index 00000000000..73322b50f2d
--- /dev/null
+++ b/tests/ui/unpretty/expanded-interpolation.stdout
@@ -0,0 +1,92 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ compile-flags: -Zunpretty=expanded
+//@ check-pass
+
+// This test covers the AST pretty-printer's insertion of parentheses in some
+// macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in
+// the syntax tree) need to be printed in order for the printed code to be valid
+// Rust syntax. We also test negative cases: the pretty-printer should not be
+// synthesizing parentheses indiscriminately; only where necessary.
+
+#![feature(let_chains)]
+#![feature(if_let_guard)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+macro_rules! expr { ($expr:expr) => { $expr }; }
+
+macro_rules! stmt { ($stmt:stmt) => { $stmt }; }
+
+fn if_let() {
+    macro_rules! if_let {
+        ($pat:pat, $expr:expr) => { if let $pat = $expr {} };
+    }
+
+    if let no_paren = true && false {}
+    if let paren_around_binary = (true && false) {};
+    if let no_paren = true {};
+
+    struct Struct {}
+    match () { _ if let no_paren = Struct {} => {} }
+}
+
+fn let_else() {
+    let no_paren = 1 + 1 else { return; };
+    let paren_around_loop = (loop {}) else { return; };
+}
+
+fn local() {
+    macro_rules! let_expr_minus_one {
+        ($pat:pat, $expr:expr) => { let $pat = $expr - 1; };
+    }
+
+    let void;
+    let no_paren = match void {} - 1;
+
+    macro_rules! let_expr_else_return {
+        ($pat:pat, $expr:expr) => { let $pat = $expr else { return; }; };
+    }
+    let 
+
+            no_paren = void() else { return; };
+}
+
+fn match_arm() {
+    macro_rules! match_arm {
+        ($pat:pat, $expr:expr) => { match () { $pat => $expr } };
+    }
+    match () {
+
+
+            no_paren => 1 - 1,
+    };
+    match () { paren_around_brace => ({ 1 }) - 1, };
+}
+
+/// https://github.com/rust-lang/rust/issues/98790
+fn stmt_boundary() {
+    macro_rules! expr_as_stmt { ($expr:expr) => { stmt!($expr) }; }
+
+    let paren_around_match;
+    (match paren_around_match {}) | true;
+
+    macro_rules! minus_one { ($expr:expr) => { expr_as_stmt!($expr - 1) }; }
+
+    let (no_paren, paren_around_loop);
+    no_paren - 1;
+    (match paren_around_match {}) - 1;
+    (match paren_around_match {})() - 1;
+    (match paren_around_match {})[0] - 1;
+    (loop { break paren_around_loop; }) - 1;
+}
+
+fn vis_inherited() {
+    macro_rules! vis_inherited {
+        ($vis:vis struct) => { $vis struct Struct; };
+    }
+    struct Struct;
+
+}
diff --git a/tests/ui/unpretty/let-else.rs b/tests/ui/unpretty/let-else.rs
deleted file mode 100644
index 4db6eca99b1..00000000000
--- a/tests/ui/unpretty/let-else.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ compile-flags: -Zunpretty=expanded
-//@ check-pass
-
-macro_rules! expr {
-    ($e:expr) => { $e };
-}
-
-fn main() {
-    let _ = expr!(1 + 1) else { return; };
-    let _ = expr!(loop {}) else { return; };
-}
diff --git a/tests/ui/unpretty/let-else.stdout b/tests/ui/unpretty/let-else.stdout
deleted file mode 100644
index 4bc4d9e085f..00000000000
--- a/tests/ui/unpretty/let-else.stdout
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(prelude_import)]
-#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-//@ compile-flags: -Zunpretty=expanded
-//@ check-pass
-
-macro_rules! expr { ($e:expr) => { $e }; }
-
-fn main() {
-    let _ = 1 + 1 else { return; };
-    let _ = (loop {}) else { return; };
-}
diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
index 23bfe3c9c2e..abd59bdbc75 100644
--- a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
+++ b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/ranged-ctor-as-fn-ptr.rs:8:40
    |
 LL |     let x: fn(u8) -> NonZeroAndOneU8 = NonZeroAndOneU8;
-   |            -------------------------   ^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
+   |            -------------------------   ^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
    |            |
    |            expected due to this
    |
diff --git a/tests/ui/unsafe/unsafe-subtyping.stderr b/tests/ui/unsafe/unsafe-subtyping.stderr
index 1cc949cf757..ddeeaa51202 100644
--- a/tests/ui/unsafe/unsafe-subtyping.stderr
+++ b/tests/ui/unsafe/unsafe-subtyping.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL | fn foo(x: Option<fn(i32)>) -> Option<unsafe fn(i32)> {
    |                               ---------------------- expected `Option<unsafe fn(i32)>` because of return type
 LL |     x
-   |     ^ expected unsafe fn, found normal fn
+   |     ^ expected unsafe fn, found safe fn
    |
    = note: expected enum `Option<unsafe fn(_)>`
               found enum `Option<fn(_)>`
diff --git a/tests/ui/unsafe/unsafe-trait-impl.stderr b/tests/ui/unsafe/unsafe-trait-impl.stderr
index 5888b674d4f..b9f2e1cc869 100644
--- a/tests/ui/unsafe/unsafe-trait-impl.stderr
+++ b/tests/ui/unsafe/unsafe-trait-impl.stderr
@@ -2,7 +2,7 @@ error[E0053]: method `len` has an incompatible type for trait
   --> $DIR/unsafe-trait-impl.rs:8:5
    |
 LL |     fn len(&self) -> u32 { *self }
-   |     ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found normal fn
+   |     ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found safe fn
    |
 note: type in trait
   --> $DIR/unsafe-trait-impl.rs:4:5
diff --git a/tests/ui/wf/wf-normalization-sized.next.stderr b/tests/ui/wf/wf-normalization-sized.next.stderr
index 599b1f3d45e..1e898fb7b78 100644
--- a/tests/ui/wf/wf-normalization-sized.next.stderr
+++ b/tests/ui/wf/wf-normalization-sized.next.stderr
@@ -1,30 +1,37 @@
-error: the type `<[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:19:10
+error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:19:11
    |
 LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
 
-error: the type `<[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:19:10
+error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:19:11
    |
 LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
+   = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: the type `<Vec<str> as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:22:10
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:22:11
    |
 LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
 
-error: the type `<Vec<str> as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:22:10
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:22:11
    |
 LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^ doesn't have a size known at compile-time
    |
+   = help: the trait `Sized` is not implemented for `str`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/wf-normalization-sized.rs b/tests/ui/wf/wf-normalization-sized.rs
index e6e24ff9e85..80b2c8803ff 100644
--- a/tests/ui/wf/wf-normalization-sized.rs
+++ b/tests/ui/wf/wf-normalization-sized.rs
@@ -17,10 +17,10 @@ impl<T: ?Sized> WellUnformed for T {
 }
 
 const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
-//[next]~^ the type
-//[next]~| the type
+//[next]~^ the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
+//[next]~| the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
 const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
-//[next]~^ the type
-//[next]~| the type
+//[next]~^ the size for values of type `str` cannot be known at compilation time
+//[next]~| the size for values of type `str` cannot be known at compilation time
 
 fn main() {}
diff --git a/triagebot.toml b/triagebot.toml
index 80820d2f297..2e45b257f81 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -867,6 +867,7 @@ compiler-team-contributors = [
     "@fmease",
     "@fee1-dead",
     "@jieyouxu",
+    "@BoxyUwU",
 ]
 compiler = [
     "compiler-team",