about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs28
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs46
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs248
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs20
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs109
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs13
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs32
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs147
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs23
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs12
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs18
-rw-r--r--compiler/rustc_data_structures/src/flock/unix.rs24
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs8
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs12
-rw-r--r--compiler/rustc_hir/src/hir.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs58
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs88
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs26
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl10
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs249
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs33
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs2
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs4
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs4
-rw-r--r--compiler/rustc_infer/messages.ftl6
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs6
-rw-r--r--compiler/rustc_interface/src/callbacks.rs43
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs9
-rw-r--r--compiler/rustc_lint/src/context.rs48
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs2
-rw-r--r--compiler/rustc_lint/src/invalid_from_utf8.rs25
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs58
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs22
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs6
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs79
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs64
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs7
-rw-r--r--compiler/rustc_middle/src/lint.rs9
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs107
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs10
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs8
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs55
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs36
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs34
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs2
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs16
-rw-r--r--compiler/rustc_middle/src/query/erase.rs8
-rw-r--r--compiler/rustc_middle/src/query/keys.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs8
-rw-r--r--compiler/rustc_middle/src/thir.rs10
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs17
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs13
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs5
-rw-r--r--compiler/rustc_middle/src/util/find_self_call.rs4
-rw-r--r--compiler/rustc_middle/src/values.rs72
-rw-r--r--compiler/rustc_mir_build/src/build/cfg.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs56
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs24
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs29
-rw-r--r--compiler/rustc_mir_build/src/build/misc.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs14
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs22
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs46
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs4
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs14
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs6
-rw-r--r--compiler/rustc_mir_transform/src/const_debuginfo.rs4
-rw-r--r--compiler/rustc_mir_transform/src/const_goto.rs4
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs10
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs10
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs46
-rw-r--r--compiler/rustc_mir_transform/src/deduplicate_blocks.rs8
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs4
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs8
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs6
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs12
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs4
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs12
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs6
-rw-r--r--compiler/rustc_mir_transform/src/required_consts.rs18
-rw-r--r--compiler/rustc_mir_transform/src/reveal_all.rs6
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs8
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs4
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs12
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs16
-rw-r--r--compiler/rustc_passes/messages.ftl4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs32
-rw-r--r--compiler/rustc_passes/src/check_const.rs4
-rw-r--r--compiler/rustc_passes/src/errors.rs10
-rw-r--r--compiler/rustc_passes/src/lang_items.rs12
-rw-r--r--compiler/rustc_query_impl/src/lib.rs6
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs37
-rw-r--r--compiler/rustc_query_system/src/dep_graph/debug.rs14
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs92
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs163
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs84
-rw-r--r--compiler/rustc_query_system/src/dep_graph/query.rs22
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs107
-rw-r--r--compiler/rustc_query_system/src/query/config.rs10
-rw-r--r--compiler/rustc_query_system/src/query/job.rs113
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs10
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs70
-rw-r--r--compiler/rustc_query_system/src/values.rs10
-rw-r--r--compiler/rustc_session/src/options.rs21
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs14
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_target/src/spec/hurd_base.rs15
-rw-r--r--compiler/rustc_target/src/spec/hurd_gnu_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs19
-rw-r--r--compiler/rustc_target/src/spec/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs1
-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.rs137
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs5
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs7
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/ops/drop.rs2
-rw-r--r--library/core/src/ops/function.rs6
-rw-r--r--library/core/src/panicking.rs3
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/io/mod.rs48
-rw-r--r--library/std/src/os/fd/owned.rs12
-rw-r--r--library/std/src/os/fd/raw.rs5
-rw-r--r--library/std/src/os/fortanix_sgx/io.rs23
-rw-r--r--library/std/src/os/hurd/fs.rs348
-rw-r--r--library/std/src/os/hurd/mod.rs6
-rw-r--r--library/std/src/os/hurd/raw.rs33
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/solid/io.rs22
-rw-r--r--library/std/src/os/unix/io/mod.rs9
-rw-r--r--library/std/src/os/unix/mod.rs2
-rw-r--r--library/std/src/os/windows/io/mod.rs3
-rw-r--r--library/std/src/os/windows/io/raw.rs6
-rw-r--r--library/std/src/process.rs2
-rw-r--r--library/std/src/process/tests.rs47
-rw-r--r--library/std/src/sys/unix/args.rs1
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fd.rs18
-rw-r--r--library/std/src/sys/unix/fs.rs60
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs4
-rw-r--r--library/std/src/sys/unix/mod.rs4
-rw-r--r--library/std/src/sys/unix/net.rs3
-rw-r--r--library/std/src/sys/unix/os.rs15
-rw-r--r--library/std/src/sys/unix/pipe.rs1
-rw-r--r--library/std/src/sys/unix/process/process_common.rs17
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs13
-rw-r--r--library/std/src/sys/unix/stack_overflow.rs2
-rw-r--r--library/std/src/sys/unix/thread.rs35
-rw-r--r--library/std/src/sys/unix/thread_local_dtor.rs2
-rw-r--r--library/std/src/sys/unix/time.rs2
-rw-r--r--library/std/src/sys_common/net.rs1
-rw-r--r--library/std/src/sys_common/process.rs4
-rw-r--r--library/unwind/src/lib.rs4
-rw-r--r--src/bootstrap/bootstrap.py4
-rw-r--r--src/bootstrap/lib.rs4
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/hurd.md35
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/librustdoc/clean/types.rs8
-rw-r--r--src/librustdoc/clean/utils.rs8
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/lib.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs5
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs8
-rw-r--r--src/tools/miri/src/helpers.rs20
-rw-r--r--src/tools/miri/src/machine.rs2
-rw-r--r--src/tools/miri/src/operator.rs14
-rw-r--r--src/tools/miri/src/shims/intrinsics/mod.rs11
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs42
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs4
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs10
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs82
-rw-r--r--tests/coverage-map/status-quo/loops_branches.cov-map264
-rw-r--r--tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir4
-rw-r--r--tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir4
-rw-r--r--tests/run-make/issue-88756-default-output/output-default.stdout3
-rw-r--r--tests/rustdoc/no-crate-filter.rs6
-rw-r--r--tests/rustdoc/rfc-2632-const-trait-impl.rs22
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs2
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr2
-rw-r--r--tests/ui/associated-inherent-types/issue-111879-1.stderr4
-rw-r--r--tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs7
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.stderr5
-rw-r--r--tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed20
-rw-r--r--tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs20
-rw-r--r--tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr43
-rw-r--r--tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs15
-rw-r--r--tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr23
-rw-r--r--tests/ui/async-await/large_moves.attribute.stderr39
-rw-r--r--tests/ui/async-await/large_moves.option.stderr39
-rw-r--r--tests/ui/borrowck/issue-92157.rs2
-rw-r--r--tests/ui/borrowck/issue-92157.stderr9
-rw-r--r--tests/ui/check-cfg/values-target-json.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/consts/fn_trait_refs.stderr62
-rw-r--r--tests/ui/consts/unstable-const-fn-in-libcore.rs8
-rw-r--r--tests/ui/consts/unstable-const-fn-in-libcore.stderr34
-rw-r--r--tests/ui/entry-point/auxiliary/bad_main_functions.rs2
-rw-r--r--tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs6
-rw-r--r--tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr12
-rw-r--r--tests/ui/error-codes/E0308.stderr8
-rw-r--r--tests/ui/extern/extern-main-fn.stderr4
-rw-r--r--tests/ui/fn/bad-main.stderr4
-rw-r--r--tests/ui/impl-trait/normalize-tait-in-const.stderr25
-rw-r--r--tests/ui/inline-const/promotion.rs22
-rw-r--r--tests/ui/inline-const/promotion.stderr14
-rw-r--r--tests/ui/intrinsics/intrinsic-alignment.rs1
-rw-r--r--tests/ui/issues/issue-9575.stderr4
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argc.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr11
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_args.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ret.stderr13
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ty.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr9
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_ret.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr9
-rw-r--r--tests/ui/lang-items/start_lang_item_args.rs24
-rw-r--r--tests/ui/lang-items/start_lang_item_args.sigpipe.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.start_ret.stderr8
-rw-r--r--tests/ui/lang-items/start_lang_item_args.too_many_args.stderr9
-rw-r--r--tests/ui/lang-items/start_lang_item_with_target_feature.rs19
-rw-r--r--tests/ui/lang-items/start_lang_item_with_target_feature.stderr11
-rw-r--r--tests/ui/lint/invalid_from_utf8.rs27
-rw-r--r--tests/ui/lint/invalid_from_utf8.stderr135
-rw-r--r--tests/ui/lint/large_assignments/box_rc_arc_allowed.rs (renamed from tests/ui/async-await/large_moves.rs)17
-rw-r--r--tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr23
-rw-r--r--tests/ui/lint/large_assignments/large_future.attribute.stderr23
-rw-r--r--tests/ui/lint/large_assignments/large_future.option.stderr23
-rw-r--r--tests/ui/lint/large_assignments/large_future.rs26
-rw-r--r--tests/ui/main-wrong-type.stderr4
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-1.rs7
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-1.stderr18
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-2.rs5
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-2.stderr12
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-3.rs2
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-3.stderr8
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-5.rs13
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-5.stderr12
-rw-r--r--tests/ui/panic-handler/panic-handler-with-target-feature.rs15
-rw-r--r--tests/ui/panic-handler/panic-handler-with-target-feature.stderr11
-rw-r--r--tests/ui/parser/issues/issue-98601-delimiter-error-1.rs9
-rw-r--r--tests/ui/parser/issues/issue-98601-delimiter-error-1.stderr16
-rw-r--r--tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs5
-rw-r--r--tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.stderr14
-rw-r--r--tests/ui/range/issue-54505-no-std.rs6
-rw-r--r--tests/ui/range/issue-54505-no-std.stderr14
-rw-r--r--tests/ui/resolve/bad-expr-path.stderr4
-rw-r--r--tests/ui/resolve/bad-expr-path2.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr49
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs11
-rw-r--r--tests/ui/stats/hir-stats.stderr32
-rw-r--r--tests/ui/structs-enums/rec-align-u64.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.rs9
-rw-r--r--tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr47
316 files changed, 3922 insertions, 2493 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a59c83de0f4..edc1e2f0b84 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1308,7 +1308,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync {
         match a {
-            Async::Yes { .. } => hir::IsAsync::Async,
+            Async::Yes { span, .. } => hir::IsAsync::Async(span),
             Async::No => hir::IsAsync::NotAsync,
         }
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 099e07e8841..f70263e9dcf 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,7 +13,7 @@ use rustc_index::IndexSlice;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
-    AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location,
+    AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
     Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
     TerminatorKind,
 };
@@ -101,12 +101,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let terminator = self.body[location.block].terminator();
         debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
         if let TerminatorKind::Call {
-            func: Operand::Constant(box Constant { literal, .. }),
+            func: Operand::Constant(box ConstOperand { const_, .. }),
             args,
             ..
         } = &terminator.kind
         {
-            if let ty::FnDef(id, _) = *literal.ty().kind() {
+            if let ty::FnDef(id, _) = *const_.ty().kind() {
                 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
                 if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
                     let closure = match args.first() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index b40e89e471d..096bf826cfb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -302,7 +302,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     if free_region.bound_region.is_named() {
                         // A named region that is actually named.
                         Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
-                    } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) {
+                    } else if tcx.asyncness(self.mir_hir_id().owner).is_async() {
                         // If we spuriously thought that the region is named, we should let the
                         // system generate a true name for error messages. Currently this can
                         // happen if we have an elided name in an async fn for example: the
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 4c69ea843c7..4c7c4982050 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -4,8 +4,7 @@ use crate::BorrowckInferCtxt;
 use rustc_index::IndexSlice;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::mir::visit::{MutVisitor, TyContext};
-use rustc_middle::mir::Constant;
-use rustc_middle::mir::{Body, Location, Promoted};
+use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
@@ -117,9 +116,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
-        let literal = constant.literal;
-        constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location));
+    fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
+        let const_ = constant.const_;
+        constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location));
         debug!("constant: {:#?}", constant);
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 0f661421cdc..60e6dcaf0b8 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -302,11 +302,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
         self.sanitize_place(place, location, context);
     }
 
-    fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
+    fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
         debug!(?constant, ?location, "visit_constant");
 
         self.super_constant(constant, location);
-        let ty = self.sanitize_type(constant, constant.literal.ty());
+        let ty = self.sanitize_type(constant, constant.const_.ty());
 
         self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
             let live_region_vid =
@@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
 
         if let Some(annotation_index) = constant.user_ty {
             if let Err(terr) = self.cx.relate_type_and_user_type(
-                constant.literal.ty(),
+                constant.const_.ty(),
                 ty::Variance::Invariant,
                 &UserTypeProjection { base: annotation_index, projs: vec![] },
                 locations,
@@ -340,20 +340,20 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                     constant,
                     "bad constant user type {:?} vs {:?}: {:?}",
                     annotation,
-                    constant.literal.ty(),
+                    constant.const_.ty(),
                     terr,
                 );
             }
         } else {
             let tcx = self.tcx();
-            let maybe_uneval = match constant.literal {
-                ConstantKind::Ty(ct) => match ct.kind() {
+            let maybe_uneval = match constant.const_ {
+                Const::Ty(ct) => match ct.kind() {
                     ty::ConstKind::Unevaluated(_) => {
-                        bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct)
+                        bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
                     }
                     _ => None,
                 },
-                ConstantKind::Unevaluated(uv, _) => Some(uv),
+                Const::Unevaluated(uv, _) => Some(uv),
                 _ => None,
             };
 
@@ -384,7 +384,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                     check_err(self, promoted_body, ty, promoted_ty);
                 } else {
                     self.cx.ascribe_user_type(
-                        constant.literal.ty(),
+                        constant.const_.ty(),
                         UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
                         locations.span(&self.cx.body),
                     );
@@ -392,7 +392,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
             } else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
                 let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
                 let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
-                let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
+                let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty;
 
                 if let Err(terr) = self.cx.eq_types(
                     literal_ty,
@@ -404,7 +404,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                 }
             }
 
-            if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() {
+            if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() {
                 let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
                 self.cx.normalize_and_prove_instantiated_predicates(
                     def_id,
@@ -1801,9 +1801,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         debug!(?op, ?location, "check_operand");
 
         if let Operand::Constant(constant) = op {
-            let maybe_uneval = match constant.literal {
-                ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
-                ConstantKind::Unevaluated(uv, _) => Some(uv),
+            let maybe_uneval = match constant.const_ {
+                Const::Val(..) | Const::Ty(_) => None,
+                Const::Unevaluated(uv, _) => Some(uv),
             };
 
             if let Some(uv) = maybe_uneval {
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 3b5f1178db5..02b52784ede 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 }
             }
 
-            BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
+            BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
                 let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
                 if self.mir_def.to_def_id() == typeck_root_def_id {
                     let args =
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 151674b2d6d..14b10ed8b9a 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -64,9 +64,9 @@ pub(crate) fn codegen_tls_ref<'tcx>(
 
 pub(crate) fn eval_mir_constant<'tcx>(
     fx: &FunctionCx<'_, '_, 'tcx>,
-    constant: &Constant<'tcx>,
+    constant: &ConstOperand<'tcx>,
 ) -> (ConstValue<'tcx>, Ty<'tcx>) {
-    let cv = fx.monomorphize(constant.literal);
+    let cv = fx.monomorphize(constant.const_);
     // This cannot fail because we checked all required_consts in advance.
     let val = cv
         .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
@@ -76,7 +76,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
 
 pub(crate) fn codegen_constant_operand<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    constant: &Constant<'tcx>,
+    constant: &ConstOperand<'tcx>,
 ) -> CValue<'tcx> {
     let (const_val, ty) = eval_mir_constant(fx, constant);
     codegen_const_value(fx, const_val, ty)
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index eba90949b5e..50bbf8105fd 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -252,8 +252,8 @@ pub(crate) fn codegen_inline_asm<'tcx>(
                 CInlineAsmOperand::Const { value }
             }
             InlineAsmOperand::SymFn { ref value } => {
-                let literal = fx.monomorphize(value.literal);
-                if let ty::FnDef(def_id, args) = *literal.ty().kind() {
+                let const_ = fx.monomorphize(value.const_);
+                if let ty::FnDef(def_id, args) = *const_.ty().kind() {
                     let instance = ty::Instance::resolve_for_fn_ptr(
                         fx.tcx,
                         ty::ParamEnv::reveal_all(),
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 7a82d05ce9e..763186a58bf 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -1,4 +1,4 @@
-use rustc_middle::mir::coverage::{CounterId, MappedExpressionIndex};
+use rustc_middle::mir::coverage::{CounterId, ExpressionId, Operand};
 
 /// Must match the layout of `LLVMRustCounterKind`.
 #[derive(Copy, Clone, Debug)]
@@ -30,11 +30,8 @@ pub struct Counter {
 }
 
 impl Counter {
-    /// Constructs a new `Counter` of kind `Zero`. For this `CounterKind`, the
-    /// `id` is not used.
-    pub fn zero() -> Self {
-        Self { kind: CounterKind::Zero, id: 0 }
-    }
+    /// A `Counter` of kind `Zero`. For this counter kind, the `id` is not used.
+    pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 };
 
     /// Constructs a new `Counter` of kind `CounterValueReference`.
     pub fn counter_value_reference(counter_id: CounterId) -> Self {
@@ -42,20 +39,16 @@ impl Counter {
     }
 
     /// Constructs a new `Counter` of kind `Expression`.
-    pub fn expression(mapped_expression_index: MappedExpressionIndex) -> Self {
-        Self { kind: CounterKind::Expression, id: mapped_expression_index.into() }
-    }
-
-    /// Returns true if the `Counter` kind is `Zero`.
-    pub fn is_zero(&self) -> bool {
-        matches!(self.kind, CounterKind::Zero)
+    pub(crate) fn expression(expression_id: ExpressionId) -> Self {
+        Self { kind: CounterKind::Expression, id: expression_id.as_u32() }
     }
 
-    /// An explicitly-named function to get the ID value, making it more obvious
-    /// that the stored value is now 0-based.
-    pub fn zero_based_id(&self) -> u32 {
-        debug_assert!(!self.is_zero(), "`id` is undefined for CounterKind::Zero");
-        self.id
+    pub(crate) fn from_operand(operand: Operand) -> Self {
+        match operand {
+            Operand::Zero => Self::ZERO,
+            Operand::Counter(id) => Self::counter_value_reference(id),
+            Operand::Expression(id) => Self::expression(id),
+        }
     }
 }
 
@@ -81,6 +74,11 @@ pub struct CounterExpression {
 }
 
 impl CounterExpression {
+    /// The dummy expression `(0 - 0)` has a representation of all zeroes,
+    /// making it marginally more efficient to initialize than `(0 + 0)`.
+    pub(crate) const DUMMY: Self =
+        Self { lhs: Counter::ZERO, kind: ExprKind::Subtract, rhs: Counter::ZERO };
+
     pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self {
         Self { kind, lhs, rhs }
     }
@@ -172,7 +170,7 @@ impl CounterMappingRegion {
     ) -> Self {
         Self {
             counter,
-            false_counter: Counter::zero(),
+            false_counter: Counter::ZERO,
             file_id,
             expanded_file_id: 0,
             start_line,
@@ -220,8 +218,8 @@ impl CounterMappingRegion {
         end_col: u32,
     ) -> Self {
         Self {
-            counter: Counter::zero(),
-            false_counter: Counter::zero(),
+            counter: Counter::ZERO,
+            false_counter: Counter::ZERO,
             file_id,
             expanded_file_id,
             start_line,
@@ -243,8 +241,8 @@ impl CounterMappingRegion {
         end_col: u32,
     ) -> Self {
         Self {
-            counter: Counter::zero(),
-            false_counter: Counter::zero(),
+            counter: Counter::ZERO,
+            false_counter: Counter::ZERO,
             file_id,
             expanded_file_id: 0,
             start_line,
@@ -268,7 +266,7 @@ impl CounterMappingRegion {
     ) -> Self {
         Self {
             counter,
-            false_counter: Counter::zero(),
+            false_counter: Counter::ZERO,
             file_id,
             expanded_file_id: 0,
             start_line,
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index f1e68af25d4..e83110dcad4 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -1,10 +1,8 @@
 use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
 
-use rustc_index::{IndexSlice, IndexVec};
-use rustc_middle::bug;
-use rustc_middle::mir::coverage::{
-    CodeRegion, CounterId, ExpressionId, MappedExpressionIndex, Op, Operand,
-};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_index::IndexVec;
+use rustc_middle::mir::coverage::{CodeRegion, CounterId, ExpressionId, Op, Operand};
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::TyCtxt;
 
@@ -128,6 +126,58 @@ impl<'tcx> FunctionCoverage<'tcx> {
         self.unreachable_regions.push(region)
     }
 
+    /// Perform some simplifications to make the final coverage mappings
+    /// slightly smaller.
+    ///
+    /// This method mainly exists to preserve the simplifications that were
+    /// already being performed by the Rust-side expression renumbering, so that
+    /// the resulting coverage mappings don't get worse.
+    pub(crate) fn simplify_expressions(&mut self) {
+        // The set of expressions that either were optimized out entirely, or
+        // have zero as both of their operands, and will therefore always have
+        // a value of zero. Other expressions that refer to these as operands
+        // can have those operands replaced with `Operand::Zero`.
+        let mut zero_expressions = FxIndexSet::default();
+
+        // For each expression, perform simplifications based on lower-numbered
+        // expressions, and then update the set of always-zero expressions if
+        // necessary.
+        // (By construction, expressions can only refer to other expressions
+        // that have lower IDs, so one simplification pass is sufficient.)
+        for (id, maybe_expression) in self.expressions.iter_enumerated_mut() {
+            let Some(expression) = maybe_expression else {
+                // If an expression is missing, it must have been optimized away,
+                // so any operand that refers to it can be replaced with zero.
+                zero_expressions.insert(id);
+                continue;
+            };
+
+            // If an operand refers to an expression that is always zero, then
+            // that operand can be replaced with `Operand::Zero`.
+            let maybe_set_operand_to_zero = |operand: &mut Operand| match &*operand {
+                Operand::Expression(id) if zero_expressions.contains(id) => {
+                    *operand = Operand::Zero;
+                }
+                _ => (),
+            };
+            maybe_set_operand_to_zero(&mut expression.lhs);
+            maybe_set_operand_to_zero(&mut expression.rhs);
+
+            // Coverage counter values cannot be negative, so if an expression
+            // involves subtraction from zero, assume that its RHS must also be zero.
+            // (Do this after simplifications that could set the LHS to zero.)
+            if let Expression { lhs: Operand::Zero, op: Op::Subtract, .. } = expression {
+                expression.rhs = Operand::Zero;
+            }
+
+            // After the above simplifications, if both operands are zero, then
+            // we know that this expression is always zero too.
+            if let Expression { lhs: Operand::Zero, rhs: Operand::Zero, .. } = expression {
+                zero_expressions.insert(id);
+            }
+        }
+    }
+
     /// Return the source hash, generated from the HIR node structure, and used to indicate whether
     /// or not the source code structure changed between different compilations.
     pub fn source_hash(&self) -> u64 {
@@ -146,8 +196,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
             self.instance
         );
 
+        let counter_expressions = self.counter_expressions();
+        // Expression IDs are indices into `self.expressions`, and on the LLVM
+        // side they will be treated as indices into `counter_expressions`, so
+        // the two vectors should correspond 1:1.
+        assert_eq!(self.expressions.len(), counter_expressions.len());
+
         let counter_regions = self.counter_regions();
-        let (counter_expressions, expression_regions) = self.expressions_with_regions();
+        let expression_regions = self.expression_regions();
         let unreachable_regions = self.unreachable_regions();
 
         let counter_regions =
@@ -163,149 +219,53 @@ impl<'tcx> FunctionCoverage<'tcx> {
         })
     }
 
-    fn expressions_with_regions(
-        &self,
-    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) {
-        let mut counter_expressions = Vec::with_capacity(self.expressions.len());
-        let mut expression_regions = Vec::with_capacity(self.expressions.len());
-        let mut new_indexes = IndexVec::from_elem_n(None, self.expressions.len());
+    /// Convert this function's coverage expression data into a form that can be
+    /// passed through FFI to LLVM.
+    fn counter_expressions(&self) -> Vec<CounterExpression> {
+        // We know that LLVM will optimize out any unused expressions before
+        // producing the final coverage map, so there's no need to do the same
+        // thing on the Rust side unless we're confident we can do much better.
+        // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
 
-        // This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or
-        // `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type
-        // and value.
-        //
-        // Expressions will be returned from this function in a sequential vector (array) of
-        // `CounterExpression`, so the expression IDs must be mapped from their original,
-        // potentially sparse set of indexes.
-        //
-        // An `Expression` as an operand will have already been encountered as an `Expression` with
-        // operands, so its new_index will already have been generated (as a 1-up index value).
-        // (If an `Expression` as an operand does not have a corresponding new_index, it was
-        // probably optimized out, after the expression was injected into the MIR, so it will
-        // get a `CounterKind::Zero` instead.)
-        //
-        // In other words, an `Expression`s at any given index can include other expressions as
-        // operands, but expression operands can only come from the subset of expressions having
-        // `expression_index`s lower than the referencing `Expression`. Therefore, it is
-        // reasonable to look up the new index of an expression operand while the `new_indexes`
-        // vector is only complete up to the current `ExpressionIndex`.
-        type NewIndexes = IndexSlice<ExpressionId, Option<MappedExpressionIndex>>;
-        let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand {
-            Operand::Zero => Some(Counter::zero()),
-            Operand::Counter(id) => Some(Counter::counter_value_reference(id)),
-            Operand::Expression(id) => {
-                self.expressions
-                    .get(id)
-                    .expect("expression id is out of range")
-                    .as_ref()
-                    // If an expression was optimized out, assume it would have produced a count
-                    // of zero. This ensures that expressions dependent on optimized-out
-                    // expressions are still valid.
-                    .map_or(Some(Counter::zero()), |_| new_indexes[id].map(Counter::expression))
-            }
-        };
-
-        for (original_index, expression) in
-            self.expressions.iter_enumerated().filter_map(|(original_index, entry)| {
-                // Option::map() will return None to filter out missing expressions. This may happen
-                // if, for example, a MIR-instrumented expression is removed during an optimization.
-                entry.as_ref().map(|expression| (original_index, expression))
-            })
-        {
-            let optional_region = &expression.region;
-            let Expression { lhs, op, rhs, .. } = *expression;
-
-            if let Some(Some((lhs_counter, mut rhs_counter))) = id_to_counter(&new_indexes, lhs)
-                .map(|lhs_counter| {
-                    id_to_counter(&new_indexes, rhs).map(|rhs_counter| (lhs_counter, rhs_counter))
-                })
-            {
-                if lhs_counter.is_zero() && op.is_subtract() {
-                    // The left side of a subtraction was probably optimized out. As an example,
-                    // a branch condition might be evaluated as a constant expression, and the
-                    // branch could be removed, dropping unused counters in the process.
-                    //
-                    // Since counters are unsigned, we must assume the result of the expression
-                    // can be no more and no less than zero. An expression known to evaluate to zero
-                    // does not need to be added to the coverage map.
-                    //
-                    // Coverage test `loops_branches.rs` includes multiple variations of branches
-                    // based on constant conditional (literal `true` or `false`), and demonstrates
-                    // that the expected counts are still correct.
-                    debug!(
-                        "Expression subtracts from zero (assume unreachable): \
-                        original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}",
-                        original_index, lhs, op, rhs, optional_region,
-                    );
-                    rhs_counter = Counter::zero();
+        self.expressions
+            .iter()
+            .map(|expression| match expression {
+                None => {
+                    // This expression ID was allocated, but we never saw the
+                    // actual expression, so it must have been optimized out.
+                    // Replace it with a dummy expression, and let LLVM take
+                    // care of omitting it from the expression list.
+                    CounterExpression::DUMMY
                 }
-                debug_assert!(
-                    lhs_counter.is_zero()
-                        // Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16`
-                        || ((lhs_counter.zero_based_id() as usize)
-                            <= usize::max(self.counters.len(), self.expressions.len())),
-                    "lhs id={} > both counters.len()={} and expressions.len()={}
-                    ({:?} {:?} {:?})",
-                    lhs_counter.zero_based_id(),
-                    self.counters.len(),
-                    self.expressions.len(),
-                    lhs_counter,
-                    op,
-                    rhs_counter,
-                );
-
-                debug_assert!(
-                    rhs_counter.is_zero()
-                        // Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16`
-                        || ((rhs_counter.zero_based_id() as usize)
-                            <= usize::max(self.counters.len(), self.expressions.len())),
-                    "rhs id={} > both counters.len()={} and expressions.len()={}
-                    ({:?} {:?} {:?})",
-                    rhs_counter.zero_based_id(),
-                    self.counters.len(),
-                    self.expressions.len(),
-                    lhs_counter,
-                    op,
-                    rhs_counter,
-                );
-
-                // Both operands exist. `Expression` operands exist in `self.expressions` and have
-                // been assigned a `new_index`.
-                let mapped_expression_index =
-                    MappedExpressionIndex::from(counter_expressions.len());
-                let expression = CounterExpression::new(
-                    lhs_counter,
-                    match op {
-                        Op::Add => ExprKind::Add,
-                        Op::Subtract => ExprKind::Subtract,
-                    },
-                    rhs_counter,
-                );
-                debug!(
-                    "Adding expression {:?} = {:?}, region: {:?}",
-                    mapped_expression_index, expression, optional_region
-                );
-                counter_expressions.push(expression);
-                new_indexes[original_index] = Some(mapped_expression_index);
-                if let Some(region) = optional_region {
-                    expression_regions.push((Counter::expression(mapped_expression_index), region));
+                &Some(Expression { lhs, op, rhs, .. }) => {
+                    // Convert the operands and operator as normal.
+                    CounterExpression::new(
+                        Counter::from_operand(lhs),
+                        match op {
+                            Op::Add => ExprKind::Add,
+                            Op::Subtract => ExprKind::Subtract,
+                        },
+                        Counter::from_operand(rhs),
+                    )
                 }
-            } else {
-                bug!(
-                    "expression has one or more missing operands \
-                      original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}",
-                    original_index,
-                    lhs,
-                    op,
-                    rhs,
-                    optional_region,
-                );
-            }
-        }
-        (counter_expressions, expression_regions.into_iter())
+            })
+            .collect::<Vec<_>>()
+    }
+
+    fn expression_regions(&self) -> Vec<(Counter, &CodeRegion)> {
+        // Find all of the expression IDs that weren't optimized out AND have
+        // an attached code region, and return the corresponding mapping as a
+        // counter/region pair.
+        self.expressions
+            .iter_enumerated()
+            .filter_map(|(id, expression)| {
+                let code_region = expression.as_ref()?.region.as_ref()?;
+                Some((Counter::expression(id), code_region))
+            })
+            .collect::<Vec<_>>()
     }
 
     fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
-        self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
+        self.unreachable_regions.iter().map(|region| (Counter::ZERO, region))
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 8ba7a11abe5..d4e77525698 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -60,8 +60,11 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
 
     // Encode coverage mappings and generate function records
     let mut function_data = Vec::new();
-    for (instance, function_coverage) in function_coverage_map {
+    for (instance, mut function_coverage) in function_coverage_map {
         debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
+        function_coverage.simplify_expressions();
+        let function_coverage = function_coverage;
+
         let mangled_function_name = tcx.symbol_name(instance).name;
         let source_hash = function_coverage.source_hash();
         let is_used = function_coverage.is_used();
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index e21148a4de1..a2190293c0b 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -660,12 +660,12 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
         }
         _ => match ct.ty().kind() {
             ty::Int(ity) => {
-                let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
+                let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
                 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
                 write!(output, "{val}")
             }
             ty::Uint(_) => {
-                let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
+                let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
                 write!(output, "{val}")
             }
             ty::Bool => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index b738a49bf11..bd0707edfd9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1098,8 +1098,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     InlineAsmOperandRef::Const { string }
                 }
                 mir::InlineAsmOperand::SymFn { ref value } => {
-                    let literal = self.monomorphize(value.literal);
-                    if let ty::FnDef(def_id, args) = *literal.ty().kind() {
+                    let const_ = self.monomorphize(value.const_);
+                    if let ty::FnDef(def_id, args) = *const_.ty().kind() {
                         let instance = ty::Instance::resolve_for_fn_ptr(
                             bx.tcx(),
                             ty::ParamEnv::reveal_all(),
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 7fec4047a95..fde4e85f966 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -13,37 +13,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn eval_mir_constant_to_operand(
         &self,
         bx: &mut Bx,
-        constant: &mir::Constant<'tcx>,
+        constant: &mir::ConstOperand<'tcx>,
     ) -> OperandRef<'tcx, Bx::Value> {
         let val = self.eval_mir_constant(constant);
         let ty = self.monomorphize(constant.ty());
         OperandRef::from_const(bx, val, ty)
     }
 
-    pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> mir::ConstValue<'tcx> {
-        self.monomorphize(constant.literal)
+    pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> {
+        self.monomorphize(constant.const_)
             .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
             .expect("erroneous constant not captured by required_consts")
     }
 
     /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
-    /// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
+    /// that the given `constant` is an `Const::Unevaluated` and must be convertible to
     /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
     ///
     /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
     pub fn eval_unevaluated_mir_constant_to_valtree(
         &self,
-        constant: &mir::Constant<'tcx>,
+        constant: &mir::ConstOperand<'tcx>,
     ) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
-        let uv = match self.monomorphize(constant.literal) {
-            mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(),
-            mir::ConstantKind::Ty(c) => match c.kind() {
+        let uv = match self.monomorphize(constant.const_) {
+            mir::Const::Unevaluated(uv, _) => uv.shrink(),
+            mir::Const::Ty(c) => match c.kind() {
                 // A constant that came from a const generic but was then used as an argument to old-style
                 // simd_shuffle (passing as argument instead of as a generic param).
                 rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)),
                 other => span_bug!(constant.span, "{other:#?}"),
             },
-            // We should never encounter `ConstantKind::Val` unless MIR opts (like const prop) evaluate
+            // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
             // a constant and write that value back into `Operand`s. This could happen, but is unlikely.
             // Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care
             // around intrinsics. For an issue to happen here, it would require a macro expanding to a
@@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn simd_shuffle_indices(
         &mut self,
         bx: &Bx,
-        constant: &mir::Constant<'tcx>,
+        constant: &mir::ConstOperand<'tcx>,
     ) -> (Bx::Value, Ty<'tcx>) {
         let ty = self.monomorphize(constant.ty());
         let val = self
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index f16aea6f34b..14b9894aad5 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -3,7 +3,7 @@ use rustc_hir::{LangItem, CRATE_HIR_ID};
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::PointerArithmetic;
 use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::INVALID_ALIGNMENT;
 use std::borrow::Borrow;
 use std::hash::Hash;
@@ -596,7 +596,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         _bin_op: mir::BinOp,
         _left: &ImmTy<'tcx>,
         _right: &ImmTy<'tcx>,
-    ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> {
         throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index bd897ffaafc..b9f88cf6352 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -24,41 +24,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         cast_ty: Ty<'tcx>,
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
+        // `cast_ty` will often be the same as `dest.ty`, but not always, since subtyping is still
+        // possible.
+        let cast_layout =
+            if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? };
         // FIXME: In which cases should we trigger UB when the source is uninit?
         match cast_kind {
             CastKind::PointerCoercion(PointerCoercion::Unsize) => {
-                let cast_ty = self.layout_of(cast_ty)?;
-                self.unsize_into(src, cast_ty, dest)?;
+                self.unsize_into(src, cast_layout, dest)?;
             }
 
             CastKind::PointerExposeAddress => {
                 let src = self.read_immediate(src)?;
-                let res = self.pointer_expose_address_cast(&src, cast_ty)?;
-                self.write_immediate(res, dest)?;
+                let res = self.pointer_expose_address_cast(&src, cast_layout)?;
+                self.write_immediate(*res, dest)?;
             }
 
             CastKind::PointerFromExposedAddress => {
                 let src = self.read_immediate(src)?;
-                let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
-                self.write_immediate(res, dest)?;
+                let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?;
+                self.write_immediate(*res, dest)?;
             }
 
             CastKind::IntToInt | CastKind::IntToFloat => {
                 let src = self.read_immediate(src)?;
-                let res = self.int_to_int_or_float(&src, cast_ty)?;
-                self.write_immediate(res, dest)?;
+                let res = self.int_to_int_or_float(&src, cast_layout)?;
+                self.write_immediate(*res, dest)?;
             }
 
             CastKind::FloatToFloat | CastKind::FloatToInt => {
                 let src = self.read_immediate(src)?;
-                let res = self.float_to_float_or_int(&src, cast_ty)?;
-                self.write_immediate(res, dest)?;
+                let res = self.float_to_float_or_int(&src, cast_layout)?;
+                self.write_immediate(*res, dest)?;
             }
 
             CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
                 let src = self.read_immediate(src)?;
-                let res = self.ptr_to_ptr(&src, cast_ty)?;
-                self.write_immediate(res, dest)?;
+                let res = self.ptr_to_ptr(&src, cast_layout)?;
+                self.write_immediate(*res, dest)?;
             }
 
             CastKind::PointerCoercion(
@@ -87,7 +90,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
                         self.write_pointer(fn_ptr, dest)?;
                     }
-                    _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty),
+                    _ => span_bug!(self.cur_span(), "reify fn pointer on {}", src.layout.ty),
                 }
             }
 
@@ -98,7 +101,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         // No change to value
                         self.write_immediate(*src, dest)?;
                     }
-                    _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty),
+                    _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {}", cast_ty),
                 }
             }
 
@@ -119,7 +122,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
                         self.write_pointer(fn_ptr, dest)?;
                     }
-                    _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
+                    _ => span_bug!(self.cur_span(), "closure fn pointer on {}", src.layout.ty),
                 }
             }
 
@@ -140,6 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             CastKind::Transmute => {
                 assert!(src.layout.is_sized());
                 assert!(dest.layout.is_sized());
+                assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely...
                 if src.layout.size != dest.layout.size {
                     let src_bytes = src.layout.size.bytes();
                     let dest_bytes = dest.layout.size.bytes();
@@ -164,62 +168,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn int_to_int_or_float(
         &self,
         src: &ImmTy<'tcx, M::Provenance>,
-        cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+        cast_to: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool());
-        assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char());
+        assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char());
 
-        Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into())
+        Ok(ImmTy::from_scalar(
+            self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?,
+            cast_to,
+        ))
     }
 
     /// Handles 'FloatToFloat' and 'FloatToInt' casts.
     pub fn float_to_float_or_int(
         &self,
         src: &ImmTy<'tcx, M::Provenance>,
-        cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+        cast_to: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         use rustc_type_ir::sty::TyKind::*;
 
-        match src.layout.ty.kind() {
+        let val = match src.layout.ty.kind() {
             // Floating point
-            Float(FloatTy::F32) => {
-                return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into());
-            }
-            Float(FloatTy::F64) => {
-                return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into());
-            }
+            Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty),
+            Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty),
             _ => {
-                bug!("Can't cast 'Float' type into {:?}", cast_ty);
+                bug!("Can't cast 'Float' type into {}", cast_to.ty);
             }
-        }
+        };
+        Ok(ImmTy::from_scalar(val, cast_to))
     }
 
     /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
     pub fn ptr_to_ptr(
         &self,
         src: &ImmTy<'tcx, M::Provenance>,
-        cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+        cast_to: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         assert!(src.layout.ty.is_any_ptr());
-        assert!(cast_ty.is_unsafe_ptr());
+        assert!(cast_to.ty.is_unsafe_ptr());
         // Handle casting any ptr to raw ptr (might be a fat ptr).
-        let dest_layout = self.layout_of(cast_ty)?;
-        if dest_layout.size == src.layout.size {
+        if cast_to.size == src.layout.size {
             // Thin or fat pointer that just hast the ptr kind of target type changed.
-            return Ok(**src);
+            return Ok(ImmTy::from_immediate(**src, cast_to));
         } else {
             // Casting the metadata away from a fat ptr.
             assert_eq!(src.layout.size, 2 * self.pointer_size());
-            assert_eq!(dest_layout.size, self.pointer_size());
+            assert_eq!(cast_to.size, self.pointer_size());
             assert!(src.layout.ty.is_unsafe_ptr());
             return match **src {
-                Immediate::ScalarPair(data, _) => Ok(data.into()),
+                Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)),
                 Immediate::Scalar(..) => span_bug!(
                     self.cur_span(),
-                    "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
+                    "{:?} input to a fat-to-thin cast ({} -> {})",
                     *src,
                     src.layout.ty,
-                    cast_ty
+                    cast_to.ty
                 ),
                 Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
             };
@@ -229,10 +232,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn pointer_expose_address_cast(
         &mut self,
         src: &ImmTy<'tcx, M::Provenance>,
-        cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+        cast_to: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
-        assert!(cast_ty.is_integral());
+        assert!(cast_to.ty.is_integral());
 
         let scalar = src.to_scalar();
         let ptr = scalar.to_pointer(self)?;
@@ -240,16 +243,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Ok(ptr) => M::expose_ptr(self, ptr)?,
             Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
         };
-        Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
+        Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
     }
 
     pub fn pointer_from_exposed_address_cast(
         &self,
         src: &ImmTy<'tcx, M::Provenance>,
-        cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+        cast_to: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         assert!(src.layout.ty.is_integral());
-        assert_matches!(cast_ty.kind(), ty::RawPtr(_));
+        assert_matches!(cast_to.ty.kind(), ty::RawPtr(_));
 
         // First cast to usize.
         let scalar = src.to_scalar();
@@ -258,12 +261,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         // Then turn address into pointer.
         let ptr = M::ptr_from_addr_cast(&self, addr)?;
-        Ok(Scalar::from_maybe_pointer(ptr, self).into())
+        Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to))
     }
 
     /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
     /// type (basically everything with a scalar layout) to int/float/char types.
-    pub fn cast_from_int_like(
+    fn cast_from_int_like(
         &self,
         scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
         src_layout: TyAndLayout<'tcx>,
@@ -298,7 +301,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             // Casts to bool are not permitted by rustc, no need to handle them here.
-            _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty),
+            _ => span_bug!(self.cur_span(), "invalid int to {} cast", cast_ty),
         })
     }
 
@@ -331,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // float -> f64
             Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
             // That's it.
-            _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty),
+            _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty),
         }
     }
 
@@ -390,7 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
                 span_bug!(
                     self.cur_span(),
-                    "invalid pointer unsizing {:?} -> {:?}",
+                    "invalid pointer unsizing {} -> {}",
                     src.layout.ty,
                     cast_ty
                 )
@@ -404,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         cast_ty: TyAndLayout<'tcx>,
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
+        trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
             (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
             | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 440ee06e7fe..49e01728ff4 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
                     let variant_index_relative_val =
                         ImmTy::from_uint(variant_index_relative, tag_layout);
-                    let tag_val = self.binary_op(
+                    let tag_val = self.wrapping_binary_op(
                         mir::BinOp::Add,
                         &variant_index_relative_val,
                         &niche_start_val,
@@ -153,19 +153,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Figure out which discriminant and variant this corresponds to.
         let index = match *tag_encoding {
             TagEncoding::Direct => {
-                let scalar = tag_val.to_scalar();
                 // Generate a specific error if `tag_val` is not an integer.
                 // (`tag_bits` itself is only used for error messages below.)
-                let tag_bits = scalar
+                let tag_bits = tag_val
+                    .to_scalar()
                     .try_to_int()
                     .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
                     .assert_bits(tag_layout.size);
                 // Cast bits from tag layout to discriminant layout.
                 // After the checks we did above, this cannot fail, as
                 // discriminants are int-like.
-                let discr_val =
-                    self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
-                let discr_bits = discr_val.assert_bits(discr_layout.size);
+                let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap();
+                let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size);
                 // Convert discriminant to variant index, and catch invalid discriminants.
                 let index = match *ty.kind() {
                     ty::Adt(adt, _) => {
@@ -208,7 +207,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
                         let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
                         let variant_index_relative_val =
-                            self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
+                            self.wrapping_binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
                         let variant_index_relative =
                             variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
                         // Check if this is in the range that indicates an actual discriminant.
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index cb14e165b5c..83f2052d0f8 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -416,7 +416,7 @@ pub(super) fn from_known_layout<'tcx>(
                 if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
                     span_bug!(
                         tcx.span,
-                        "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
+                        "expected type differs from actual type.\nexpected: {}\nactual: {}",
                         known_layout.ty,
                         check_layout.ty,
                     );
@@ -712,7 +712,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             ty::Foreign(_) => Ok(None),
 
-            _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty),
+            _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty),
         }
     }
     #[inline]
@@ -982,7 +982,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
                 ty::Bound(..)
                 | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-                    bug!("`is_very_trivially_sized` applied to unexpected type: {:?}", ty)
+                    bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)
                 }
             }
         }
@@ -1089,7 +1089,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn eval_mir_constant(
         &self,
-        val: &mir::ConstantKind<'tcx>,
+        val: &mir::Const<'tcx>,
         span: Option<Span>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 775a834f2ee..2b26dbbba98 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -307,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let dist = {
                     // Addresses are unsigned, so this is a `usize` computation. We have to do the
                     // overflow check separately anyway.
-                    let (val, overflowed, _ty) = {
+                    let (val, overflowed) = {
                         let a_offset = ImmTy::from_uint(a_offset, usize_layout);
                         let b_offset = ImmTy::from_uint(b_offset, usize_layout);
                         self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?
@@ -324,7 +324,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         // The signed form of the intrinsic allows this. If we interpret the
                         // difference as isize, we'll get the proper signed difference. If that
                         // seems *positive*, they were more than isize::MAX apart.
-                        let dist = val.to_target_isize(self)?;
+                        let dist = val.to_scalar().to_target_isize(self)?;
                         if dist >= 0 {
                             throw_ub_custom!(
                                 fluent::const_eval_offset_from_underflow,
@@ -334,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         dist
                     } else {
                         // b >= a
-                        let dist = val.to_target_isize(self)?;
+                        let dist = val.to_scalar().to_target_isize(self)?;
                         // If converting to isize produced a *negative* result, we had an overflow
                         // because they were more than isize::MAX apart.
                         if dist < 0 {
@@ -504,9 +504,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Performs an exact division, resulting in undefined behavior where
         // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
         // First, check x % y != 0 (or if that computation overflows).
-        let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
+        let (res, overflow) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
         assert!(!overflow); // All overflow is UB, so this should never return on overflow.
-        if res.assert_bits(a.layout.size) != 0 {
+        if res.to_scalar().assert_bits(a.layout.size) != 0 {
             throw_ub_custom!(
                 fluent::const_eval_exact_div_has_remainder,
                 a = format!("{a}"),
@@ -524,7 +524,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         r: &ImmTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
-        let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
+        let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?;
         Ok(if overflowed {
             let size = l.layout.size;
             let num_bits = size.bits();
@@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
             }
         } else {
-            val
+            val.to_scalar()
         })
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index c9fd2102418..aaa674a598f 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -9,7 +9,7 @@ use std::hash::Hash;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi as CallAbi;
@@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment;
 
 use super::{
     AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
-    InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, Scalar,
+    InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance,
 };
 
 /// Data returned by Machine::stack_pop,
@@ -238,7 +238,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, Self::Provenance>,
         right: &ImmTy<'tcx, Self::Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>;
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>;
 
     /// Called before writing the specified `local` of the `frame`.
     /// Since writing a ZST is not actually accessing memory or locals, this is never invoked
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index fdda98a50e8..a32ea204f98 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -8,7 +8,7 @@ use either::{Either, Left, Right};
 use rustc_hir::def::Namespace;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
-use rustc_middle::ty::{ConstInt, Ty};
+use rustc_middle::ty::{ConstInt, Ty, TyCtxt};
 use rustc_middle::{mir, ty};
 use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
 
@@ -165,7 +165,15 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline(always)]
     pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
-        debug_assert!(layout.is_sized(), "immediates must be sized");
+        debug_assert!(
+            match (imm, layout.abi) {
+                (Immediate::Scalar(..), Abi::Scalar(..)) => true,
+                (Immediate::ScalarPair(..), Abi::ScalarPair(..)) => true,
+                (Immediate::Uninit, _) if layout.is_sized() => true,
+                _ => false,
+            },
+            "immediate {imm:?} does not fit to layout {layout:?}",
+        );
         ImmTy { imm, layout }
     }
 
@@ -195,6 +203,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     }
 
     #[inline]
+    pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
+        let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap();
+        Self::from_scalar(Scalar::from_bool(b), layout)
+    }
+
+    #[inline]
     pub fn to_const_int(self) -> ConstInt {
         assert!(self.layout.ty.is_integral());
         let int = self.to_scalar().assert_int();
@@ -448,7 +462,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     alloc_range(Size::ZERO, size),
                     /*read_provenance*/ matches!(s, abi::Pointer(_)),
                 )?;
-                Some(ImmTy { imm: scalar.into(), layout: mplace.layout })
+                Some(ImmTy::from_scalar(scalar, mplace.layout))
             }
             Abi::ScalarPair(
                 abi::Scalar::Initialized { value: a, .. },
@@ -468,7 +482,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     alloc_range(b_offset, b_size),
                     /*read_provenance*/ matches!(b, abi::Pointer(_)),
                 )?;
-                Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })
+                Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout))
             }
             _ => {
                 // Neither a scalar nor scalar pair.
@@ -514,11 +528,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Abi::Scalar(abi::Scalar::Initialized { .. })
                 | Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. })
         ) {
-            span_bug!(
-                self.cur_span(),
-                "primitive read not possible for type: {:?}",
-                op.layout().ty
-            );
+            span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty);
         }
         let imm = self.read_immediate_raw(op)?.right().unwrap();
         if matches!(*imm, Immediate::Uninit) {
@@ -669,7 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 )?)?,
                 op.layout,
             ),
-            "eval_place of a MIR place with type {:?} produced an interpreter operand with type {:?}",
+            "eval_place of a MIR place with type {:?} produced an interpreter operand with type {}",
             mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
             op.layout.ty,
         );
@@ -692,7 +702,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             Constant(constant) => {
                 let c =
-                    self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
+                    self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?;
 
                 // This can still fail:
                 // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index eb064578067..b084864f3a7 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -1,7 +1,7 @@
 use rustc_apfloat::Float;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
-use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, FloatTy, Ty};
 use rustc_span::symbol::sym;
 use rustc_target::abi::Abi;
@@ -20,9 +20,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         right: &ImmTy<'tcx, M::Provenance>,
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
+        let (val, overflowed) = self.overflowing_binary_op(op, &left, &right)?;
         debug_assert_eq!(
-            Ty::new_tup(self.tcx.tcx, &[ty, self.tcx.types.bool]),
+            Ty::new_tup(self.tcx.tcx, &[val.layout.ty, self.tcx.types.bool]),
             dest.layout.ty,
             "type mismatch for result of {op:?}",
         );
@@ -30,7 +30,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         if let Abi::ScalarPair(..) = dest.layout.abi {
             // We can use the optimized path and avoid `place_field` (which might do
             // `force_allocation`).
-            let pair = Immediate::ScalarPair(val, Scalar::from_bool(overflowed));
+            let pair = Immediate::ScalarPair(val.to_scalar(), Scalar::from_bool(overflowed));
             self.write_immediate(pair, dest)?;
         } else {
             assert!(self.tcx.sess.opts.unstable_opts.randomize_layout);
@@ -38,7 +38,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // do a component-wise write here. This code path is slower than the above because
             // `place_field` will have to `force_allocate` locals here.
             let val_field = self.project_field(dest, 0)?;
-            self.write_scalar(val, &val_field)?;
+            self.write_scalar(val.to_scalar(), &val_field)?;
             let overflowed_field = self.project_field(dest, 1)?;
             self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?;
         }
@@ -54,9 +54,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         right: &ImmTy<'tcx, M::Provenance>,
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
-        assert_eq!(ty, dest.layout.ty, "type mismatch for result of {op:?}");
-        self.write_scalar(val, dest)
+        let val = self.wrapping_binary_op(op, left, right)?;
+        assert_eq!(val.layout.ty, dest.layout.ty, "type mismatch for result of {op:?}");
+        self.write_immediate(*val, dest)
     }
 }
 
@@ -66,7 +66,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         bin_op: mir::BinOp,
         l: char,
         r: char,
-    ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
+    ) -> (ImmTy<'tcx, M::Provenance>, bool) {
         use rustc_middle::mir::BinOp::*;
 
         let res = match bin_op {
@@ -78,7 +78,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Ge => l >= r,
             _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op),
         };
-        (Scalar::from_bool(res), false, self.tcx.types.bool)
+        (ImmTy::from_bool(res, *self.tcx), false)
     }
 
     fn binary_bool_op(
@@ -86,7 +86,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         bin_op: mir::BinOp,
         l: bool,
         r: bool,
-    ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
+    ) -> (ImmTy<'tcx, M::Provenance>, bool) {
         use rustc_middle::mir::BinOp::*;
 
         let res = match bin_op {
@@ -101,33 +101,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             BitXor => l ^ r,
             _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op),
         };
-        (Scalar::from_bool(res), false, self.tcx.types.bool)
+        (ImmTy::from_bool(res, *self.tcx), false)
     }
 
     fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>(
         &self,
         bin_op: mir::BinOp,
-        ty: Ty<'tcx>,
+        layout: TyAndLayout<'tcx>,
         l: F,
         r: F,
-    ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
+    ) -> (ImmTy<'tcx, M::Provenance>, bool) {
         use rustc_middle::mir::BinOp::*;
 
-        let (val, ty) = match bin_op {
-            Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
-            Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
-            Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
-            Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
-            Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
-            Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
-            Add => ((l + r).value.into(), ty),
-            Sub => ((l - r).value.into(), ty),
-            Mul => ((l * r).value.into(), ty),
-            Div => ((l / r).value.into(), ty),
-            Rem => ((l % r).value.into(), ty),
+        let val = match bin_op {
+            Eq => ImmTy::from_bool(l == r, *self.tcx),
+            Ne => ImmTy::from_bool(l != r, *self.tcx),
+            Lt => ImmTy::from_bool(l < r, *self.tcx),
+            Le => ImmTy::from_bool(l <= r, *self.tcx),
+            Gt => ImmTy::from_bool(l > r, *self.tcx),
+            Ge => ImmTy::from_bool(l >= r, *self.tcx),
+            Add => ImmTy::from_scalar((l + r).value.into(), layout),
+            Sub => ImmTy::from_scalar((l - r).value.into(), layout),
+            Mul => ImmTy::from_scalar((l * r).value.into(), layout),
+            Div => ImmTy::from_scalar((l / r).value.into(), layout),
+            Rem => ImmTy::from_scalar((l % r).value.into(), layout),
             _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
         };
-        (val, false, ty)
+        (val, false)
     }
 
     fn binary_int_op(
@@ -138,7 +138,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         left_layout: TyAndLayout<'tcx>,
         r: u128,
         right_layout: TyAndLayout<'tcx>,
-    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
         use rustc_middle::mir::BinOp::*;
 
         let throw_ub_on_overflow = match bin_op {
@@ -200,19 +200,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 );
             }
 
-            return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty));
+            return Ok((ImmTy::from_uint(truncated, left_layout), overflow));
         }
 
         // For the remaining ops, the types must be the same on both sides
         if left_layout.ty != right_layout.ty {
             span_bug!(
                 self.cur_span(),
-                "invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
-                bin_op,
-                l,
-                left_layout.ty,
-                r,
-                right_layout.ty,
+                "invalid asymmetric binary op {bin_op:?}: {l:?} ({l_ty}), {r:?} ({r_ty})",
+                l_ty = left_layout.ty,
+                r_ty = right_layout.ty,
             )
         }
 
@@ -230,7 +227,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             if let Some(op) = op {
                 let l = self.sign_extend(l, left_layout) as i128;
                 let r = self.sign_extend(r, right_layout) as i128;
-                return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool));
+                return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false));
             }
             let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
                 Div if r == 0 => throw_ub!(DivisionByZero),
@@ -267,22 +264,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
                     throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
                 }
-                return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty));
+                return Ok((ImmTy::from_uint(truncated, left_layout), overflow));
             }
         }
 
-        let (val, ty) = match bin_op {
-            Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
-            Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
+        let val = match bin_op {
+            Eq => ImmTy::from_bool(l == r, *self.tcx),
+            Ne => ImmTy::from_bool(l != r, *self.tcx),
 
-            Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
-            Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
-            Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
-            Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
+            Lt => ImmTy::from_bool(l < r, *self.tcx),
+            Le => ImmTy::from_bool(l <= r, *self.tcx),
+            Gt => ImmTy::from_bool(l > r, *self.tcx),
+            Ge => ImmTy::from_bool(l >= r, *self.tcx),
 
-            BitOr => (Scalar::from_uint(l | r, size), left_layout.ty),
-            BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty),
-            BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty),
+            BitOr => ImmTy::from_uint(l | r, left_layout),
+            BitAnd => ImmTy::from_uint(l & r, left_layout),
+            BitXor => ImmTy::from_uint(l ^ r, left_layout),
 
             Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => {
                 assert!(!left_layout.abi.is_signed());
@@ -304,12 +301,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
                     throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
                 }
-                return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty));
+                return Ok((ImmTy::from_uint(truncated, left_layout), overflow));
             }
 
             _ => span_bug!(
                 self.cur_span(),
-                "invalid binary op {:?}: {:?}, {:?} (both {:?})",
+                "invalid binary op {:?}: {:?}, {:?} (both {})",
                 bin_op,
                 l,
                 r,
@@ -317,7 +314,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ),
         };
 
-        Ok((val, false, ty))
+        Ok((val, false))
     }
 
     fn binary_ptr_op(
@@ -325,7 +322,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, M::Provenance>,
         right: &ImmTy<'tcx, M::Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
         use rustc_middle::mir::BinOp::*;
 
         match bin_op {
@@ -336,7 +333,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty;
 
                 let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
-                Ok((Scalar::from_maybe_pointer(offset_ptr, self), false, left.layout.ty))
+                Ok((
+                    ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout),
+                    false,
+                ))
             }
 
             // Fall back to machine hook so Miri can support more pointer ops.
@@ -344,16 +344,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
-    /// Returns the result of the specified operation, whether it overflowed, and
-    /// the result type.
+    /// Returns the result of the specified operation, and whether it overflowed.
     pub fn overflowing_binary_op(
         &self,
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, M::Provenance>,
         right: &ImmTy<'tcx, M::Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
         trace!(
-            "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
+            "Running binary op {:?}: {:?} ({}), {:?} ({})",
             bin_op,
             *left,
             left.layout.ty,
@@ -376,15 +375,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             ty::Float(fty) => {
                 assert_eq!(left.layout.ty, right.layout.ty);
-                let ty = left.layout.ty;
+                let layout = left.layout;
                 let left = left.to_scalar();
                 let right = right.to_scalar();
                 Ok(match fty {
                     FloatTy::F32 => {
-                        self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?)
+                        self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?)
                     }
                     FloatTy::F64 => {
-                        self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?)
+                        self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?)
                     }
                 })
             }
@@ -392,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // the RHS type can be different, e.g. for shifts -- but it has to be integral, too
                 assert!(
                     right.layout.ty.is_integral(),
-                    "Unexpected types for BinOp: {:?} {:?} {:?}",
+                    "Unexpected types for BinOp: {} {:?} {}",
                     left.layout.ty,
                     bin_op,
                     right.layout.ty
@@ -407,7 +406,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // (Even when both sides are pointers, their type might differ, see issue #91636)
                 assert!(
                     right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(),
-                    "Unexpected types for BinOp: {:?} {:?} {:?}",
+                    "Unexpected types for BinOp: {} {:?} {}",
                     left.layout.ty,
                     bin_op,
                     right.layout.ty
@@ -417,22 +416,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             _ => span_bug!(
                 self.cur_span(),
-                "Invalid MIR: bad LHS type for binop: {:?}",
+                "Invalid MIR: bad LHS type for binop: {}",
                 left.layout.ty
             ),
         }
     }
 
-    /// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows.
     #[inline]
-    pub fn binary_op(
+    pub fn wrapping_binary_op(
         &self,
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, M::Provenance>,
         right: &ImmTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
-        let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
-        Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
+        let (val, _overflow) = self.overflowing_binary_op(bin_op, left, right)?;
+        Ok(val)
     }
 
     /// Returns the result of the specified operation, whether it overflowed, and
@@ -441,12 +439,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         un_op: mir::UnOp,
         val: &ImmTy<'tcx, M::Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
         use rustc_middle::mir::UnOp::*;
 
         let layout = val.layout;
         let val = val.to_scalar();
-        trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty);
+        trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
 
         match layout.ty.kind() {
             ty::Bool => {
@@ -455,7 +453,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     Not => !val,
                     _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
                 };
-                Ok((Scalar::from_bool(res), false, self.tcx.types.bool))
+                Ok((ImmTy::from_bool(res, *self.tcx), false))
             }
             ty::Float(fty) => {
                 let res = match (un_op, fty) {
@@ -463,7 +461,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
                     _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op),
                 };
-                Ok((res, false, layout.ty))
+                Ok((ImmTy::from_scalar(res, layout), false))
             }
             _ => {
                 assert!(layout.ty.is_integral());
@@ -482,17 +480,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         (truncated, overflow || self.sign_extend(truncated, layout) != res)
                     }
                 };
-                Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty))
+                Ok((ImmTy::from_uint(res, layout), overflow))
             }
         }
     }
 
-    pub fn unary_op(
+    #[inline]
+    pub fn wrapping_unary_op(
         &self,
         un_op: mir::UnOp,
         val: &ImmTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
-        let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
-        Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
+        let (val, _overflow) = self.overflowing_unary_op(un_op, val)?;
+        Ok(val)
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index fb9aa9d3abe..503004cbbe1 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -460,7 +460,7 @@ where
         trace!("deref to {} on {:?}", val.layout.ty, *val);
 
         if val.layout.ty.is_box() {
-            bug!("dereferencing {:?}", val.layout.ty);
+            bug!("dereferencing {}", val.layout.ty);
         }
 
         let mplace = self.ref_to_mplace(&val)?;
@@ -582,7 +582,7 @@ where
                 )?)?,
                 place.layout,
             ),
-            "eval_place of a MIR place with type {:?} produced an interpreter place with type {:?}",
+            "eval_place of a MIR place with type {:?} produced an interpreter place with type {}",
             mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
             place.layout.ty,
         );
@@ -835,7 +835,7 @@ where
         if !allow_transmute && !layout_compat {
             span_bug!(
                 self.cur_span(),
-                "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
+                "type mismatch when copying!\nsrc: {},\ndest: {}",
                 src.layout().ty,
                 dest.layout().ty,
             );
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index cf1f7ff75e1..284e13407f7 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -177,7 +177,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             UnaryOp(un_op, ref operand) => {
                 // The operand always has the same type as the result.
                 let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
-                let val = self.unary_op(un_op, &val)?;
+                let val = self.wrapping_unary_op(un_op, &val)?;
                 assert_eq!(val.layout, dest.layout, "layout mismatch for result of {un_op:?}");
                 self.write_immediate(*val, &dest)?;
             }
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index e15499bc68d..578dd6622aa 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -98,14 +98,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 for (const_int, target) in targets.iter() {
                     // Compare using MIR BinOp::Eq, to also support pointer values.
                     // (Avoiding `self.binary_op` as that does some redundant layout computation.)
-                    let res = self
-                        .overflowing_binary_op(
-                            mir::BinOp::Eq,
-                            &discr,
-                            &ImmTy::from_uint(const_int, discr.layout),
-                        )?
-                        .0;
-                    if res.to_bool()? {
+                    let res = self.wrapping_binary_op(
+                        mir::BinOp::Eq,
+                        &discr,
+                        &ImmTy::from_uint(const_int, discr.layout),
+                    )?;
+                    if res.to_scalar().to_bool()? {
                         target_block = target;
                         break;
                     }
@@ -151,7 +149,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     }
                     _ => span_bug!(
                         terminator.source_info.span,
-                        "invalid callee of type {:?}",
+                        "invalid callee of type {}",
                         func.layout.ty
                     ),
                 };
@@ -681,10 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             self.storage_live(local)?;
                             // Must be a tuple
                             let ty::Tuple(fields) = ty.kind() else {
-                                span_bug!(
-                                    self.cur_span(),
-                                    "non-tuple type for `spread_arg`: {ty:?}"
-                                )
+                                span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
                             };
                             for (i, field_ty) in fields.iter().enumerate() {
                                 let dest = dest.project_deeper(
@@ -926,7 +921,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         target: mir::BasicBlock,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
-        trace!("drop_in_place: {:?},\n  {:?}, {:?}", *place, place.layout.ty, instance);
+        trace!("drop_in_place: {:?},\n  instance={:?}", place, instance);
         // We take the address of the object. This may well be unaligned, which is fine
         // for us here. However, unaligned accesses will probably make the actual drop
         // implementation fail -- a problem shared by rustc.
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index f288ddc25d3..129e74425b6 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -167,7 +167,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
                 false
             }
 
-            hir::ConstContext::Const | hir::ConstContext::Static(_) => {
+            hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
                 let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
                     .into_engine(ccx.tcx, &ccx.body)
                     .iterate_to_fixpoint()
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index b1b2859ef9d..34e9b76c484 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -346,8 +346,8 @@ where
     };
 
     // Check the qualifs of the value of `const` items.
-    let uneval = match constant.literal {
-        ConstantKind::Ty(ct)
+    let uneval = match constant.const_ {
+        Const::Ty(ct)
             if matches!(
                 ct.kind(),
                 ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
@@ -355,11 +355,11 @@ where
         {
             None
         }
-        ConstantKind::Ty(c) => {
+        Const::Ty(c) => {
             bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
         }
-        ConstantKind::Unevaluated(uv, _) => Some(uv),
-        ConstantKind::Val(..) => None,
+        Const::Unevaluated(uv, _) => Some(uv),
+        Const::Val(..) => None,
     };
 
     if let Some(mir::UnevaluatedConst { def, args: _, promoted }) = uneval {
@@ -383,5 +383,5 @@ where
     }
 
     // Otherwise use the qualifs of the type.
-    Q::in_any_value_of_ty(cx, constant.literal.ty())
+    Q::in_any_value_of_ty(cx, constant.const_.ty())
 }
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index d79c65f1d1f..4a9977add78 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -372,7 +372,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                                     StatementKind::Assign(box (
                                         _,
                                         Rvalue::Use(Operand::Constant(c)),
-                                    )) => c.literal.try_eval_target_usize(self.tcx, self.param_env),
+                                    )) => c.const_.try_eval_target_usize(self.tcx, self.param_env),
                                     _ => None,
                                 }
                             } else {
@@ -554,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                             // Integer division: the RHS must be a non-zero const.
                             let const_val = match rhs {
                                 Operand::Constant(c) => {
-                                    c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty)
+                                    c.const_.try_eval_bits(self.tcx, self.param_env)
                                 }
                                 _ => None,
                             };
@@ -644,7 +644,7 @@ impl<'tcx> Validator<'_, 'tcx> {
         // Everywhere else, we require `#[rustc_promotable]` on the callee.
         let promote_all_const_fn = matches!(
             self.const_kind,
-            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
+            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false })
         );
         if !promote_all_const_fn {
             if let ty::FnDef(def_id, _) = *fn_ty.kind() {
@@ -766,10 +766,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                     if self.keep_original {
                         rhs.clone()
                     } else {
-                        let unit = Rvalue::Use(Operand::Constant(Box::new(Constant {
+                        let unit = Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
                             span: statement.source_info.span,
                             user_ty: None,
-                            literal: ConstantKind::zero_sized(self.tcx.types.unit),
+                            const_: Const::zero_sized(self.tcx.types.unit),
                         })));
                         mem::replace(rhs, unit)
                     },
@@ -844,10 +844,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def));
                 let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) };
 
-                Operand::Constant(Box::new(Constant {
+                Operand::Constant(Box::new(ConstOperand {
                     span,
                     user_ty: None,
-                    literal: ConstantKind::Unevaluated(uneval, ty),
+                    const_: Const::Unevaluated(uneval, ty),
                 }))
             };
 
@@ -1041,8 +1041,8 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
         if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
             &block.terminator
         {
-            if let Operand::Constant(box Constant { literal, .. }) = func {
-                if let ty::FnDef(def_id, _) = *literal.ty().kind() {
+            if let Operand::Constant(box ConstOperand { const_, .. }) = func {
+                if let ty::FnDef(def_id, _) = *const_.ty().kind() {
                     if destination == place {
                         if ccx.tcx.is_const_fn(def_id) {
                             return true;
diff --git a/compiler/rustc_data_structures/src/flock/unix.rs b/compiler/rustc_data_structures/src/flock/unix.rs
index 4e5297d582e..eff9e8f838f 100644
--- a/compiler/rustc_data_structures/src/flock/unix.rs
+++ b/compiler/rustc_data_structures/src/flock/unix.rs
@@ -21,8 +21,16 @@ impl Lock {
         let lock_type = if exclusive { libc::F_WRLCK } else { libc::F_RDLCK };
 
         let mut flock: libc::flock = unsafe { mem::zeroed() };
-        flock.l_type = lock_type as libc::c_short;
-        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        #[cfg(not(all(target_os = "hurd", target_arch = "x86")))]
+        {
+            flock.l_type = lock_type as libc::c_short;
+            flock.l_whence = libc::SEEK_SET as libc::c_short;
+        }
+        #[cfg(all(target_os = "hurd", target_arch = "x86"))]
+        {
+            flock.l_type = lock_type as libc::c_int;
+            flock.l_whence = libc::SEEK_SET as libc::c_int;
+        }
         flock.l_start = 0;
         flock.l_len = 0;
 
@@ -39,8 +47,16 @@ impl Lock {
 impl Drop for Lock {
     fn drop(&mut self) {
         let mut flock: libc::flock = unsafe { mem::zeroed() };
-        flock.l_type = libc::F_UNLCK as libc::c_short;
-        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        #[cfg(not(all(target_os = "hurd", target_arch = "x86")))]
+        {
+            flock.l_type = libc::F_UNLCK as libc::c_short;
+            flock.l_whence = libc::SEEK_SET as libc::c_short;
+        }
+        #[cfg(all(target_os = "hurd", target_arch = "x86"))]
+        {
+            flock.l_type = libc::F_UNLCK as libc::c_int;
+            flock.l_whence = libc::SEEK_SET as libc::c_int;
+        }
         flock.l_start = 0;
         flock.l_len = 0;
 
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 3fd087b1d5e..470f318eb33 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -151,7 +151,12 @@ impl fmt::Display for DiagnosticLocation {
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
 pub enum DiagnosticId {
     Error(String),
-    Lint { name: String, has_future_breakage: bool, is_force_warn: bool },
+    Lint {
+        name: String,
+        /// Indicates whether this lint should show up in cargo's future breakage report.
+        has_future_breakage: bool,
+        is_force_warn: bool,
+    },
 }
 
 /// A "sub"-diagnostic attached to a parent diagnostic.
@@ -301,6 +306,7 @@ impl Diagnostic {
         }
     }
 
+    /// Indicates whether this diagnostic should show up in cargo's future breakage report.
     pub fn has_future_breakage(&self) -> bool {
         match self.code {
             Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index a170e3a8943..4f77f09b26e 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -161,7 +161,7 @@ impl IntoDiagnosticArg for hir::ConstContext {
         DiagnosticArgValue::Str(Cow::Borrowed(match self {
             hir::ConstContext::ConstFn => "const_fn",
             hir::ConstContext::Static(_) => "static",
-            hir::ConstContext::Const => "const",
+            hir::ConstContext::Const { .. } => "const",
         }))
     }
 }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 990bd2d1cc9..b747a62b864 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -519,7 +519,7 @@ pub struct HandlerFlags {
     /// If false, warning-level lints are suppressed.
     /// (rustc: see `--allow warnings` and `--cap-lints`)
     pub can_emit_warnings: bool,
-    /// If true, error-level diagnostics are upgraded to bug-level.
+    /// If Some, the Nth error-level diagnostic is upgraded to bug-level.
     /// (rustc: see `-Z treat-err-as-bug`)
     pub treat_err_as_bug: Option<NonZeroUsize>,
     /// If true, immediately emit diagnostics that would otherwise be buffered.
@@ -1719,19 +1719,17 @@ impl HandlerInner {
             match (
                 self.err_count() + self.lint_err_count,
                 self.delayed_bug_count(),
-                self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
+                self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(),
             ) {
                 (1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
                 (0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"),
-                (count, delayed_count, as_bug) => {
+                (count, delayed_count, val) => {
                     if delayed_count > 0 {
                         panic!(
-                            "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={as_bug}`",
+                            "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={val}`",
                         )
                     } else {
-                        panic!(
-                            "aborting after {count} errors due to `-Z treat-err-as-bug={as_bug}`",
-                        )
+                        panic!("aborting after {count} errors due to `-Z treat-err-as-bug={val}`")
                     }
                 }
             }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index cb78da42597..3eec66611ed 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1581,8 +1581,8 @@ pub enum BodyOwnerKind {
     /// Closures
     Closure,
 
-    /// Constants and associated constants.
-    Const,
+    /// Constants and associated constants, also including inline constants.
+    Const { inline: bool },
 
     /// Initializer of a `static` item.
     Static(Mutability),
@@ -1592,7 +1592,7 @@ impl BodyOwnerKind {
     pub fn is_fn_or_closure(self) -> bool {
         match self {
             BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
-            BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false,
+            BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false,
         }
     }
 }
@@ -1615,7 +1615,7 @@ pub enum ConstContext {
     ///
     /// For the most part, other contexts are treated just like a regular `const`, so they are
     /// lumped into the same category.
-    Const,
+    Const { inline: bool },
 }
 
 impl ConstContext {
@@ -1624,7 +1624,7 @@ impl ConstContext {
     /// E.g. `const` or `static mut`.
     pub fn keyword_name(self) -> &'static str {
         match self {
-            Self::Const => "const",
+            Self::Const { .. } => "const",
             Self::Static(Mutability::Not) => "static",
             Self::Static(Mutability::Mut) => "static mut",
             Self::ConstFn => "const fn",
@@ -1637,7 +1637,7 @@ impl ConstContext {
 impl fmt::Display for ConstContext {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            Self::Const => write!(f, "constant"),
+            Self::Const { .. } => write!(f, "constant"),
             Self::Static(_) => write!(f, "static"),
             Self::ConstFn => write!(f, "constant function"),
         }
@@ -2853,13 +2853,13 @@ impl ImplicitSelfKind {
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
 pub enum IsAsync {
-    Async,
+    Async(Span),
     NotAsync,
 }
 
 impl IsAsync {
     pub fn is_async(self) -> bool {
-        self == IsAsync::Async
+        matches!(self, IsAsync::Async(_))
     }
 }
 
@@ -3296,7 +3296,7 @@ pub struct FnHeader {
 
 impl FnHeader {
     pub fn is_async(&self) -> bool {
-        matches!(&self.asyncness, IsAsync::Async)
+        matches!(&self.asyncness, IsAsync::Async(_))
     }
 
     pub fn is_const(&self) -> bool {
@@ -4091,10 +4091,10 @@ mod size_asserts {
     static_assert_size!(GenericBound<'_>, 48);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
-    static_assert_size!(ImplItem<'_>, 80);
-    static_assert_size!(ImplItemKind<'_>, 32);
-    static_assert_size!(Item<'_>, 80);
-    static_assert_size!(ItemKind<'_>, 48);
+    static_assert_size!(ImplItem<'_>, 88);
+    static_assert_size!(ImplItemKind<'_>, 40);
+    static_assert_size!(Item<'_>, 88);
+    static_assert_size!(ItemKind<'_>, 56);
     static_assert_size!(Local<'_>, 64);
     static_assert_size!(Param<'_>, 32);
     static_assert_size!(Pat<'_>, 72);
@@ -4105,8 +4105,8 @@ mod size_asserts {
     static_assert_size!(Res, 12);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
-    static_assert_size!(TraitItem<'_>, 80);
-    static_assert_size!(TraitItemKind<'_>, 40);
+    static_assert_size!(TraitItem<'_>, 88);
+    static_assert_size!(TraitItemKind<'_>, 48);
     static_assert_size!(Ty<'_>, 48);
     static_assert_size!(TyKind<'_>, 32);
     // tidy-alphabetical-end
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 38f19aa09ad..7be18a36d63 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -595,7 +595,7 @@ fn compare_asyncness<'tcx>(
     trait_m: ty::AssocItem,
     delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
-    if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+    if tcx.asyncness(trait_m.def_id).is_async() {
         match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
             ty::Alias(ty::Opaque, ..) => {
                 // allow both `async fn foo()` and `fn foo() -> impl Future`
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index fcaefe0261b..3cd3f5bcfdd 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -11,8 +11,8 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::ops::Not;
 
+use super::check_function_signature;
 use crate::errors;
-use crate::require_same_types;
 
 pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
     match tcx.entry_fn(()) {
@@ -112,7 +112,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     }
 
     let main_asyncness = tcx.asyncness(main_def_id);
-    if let hir::IsAsync::Async = main_asyncness {
+    if main_asyncness.is_async() {
         let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
         tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
         error = true;
@@ -162,33 +162,33 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
             error = true;
         }
         // now we can take the return type of the given main function
-        expected_return_type = main_fnsig.output();
+        expected_return_type = norm_return_ty;
     } else {
         // standard () main return type
-        expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx));
+        expected_return_type = tcx.types.unit;
     }
 
     if error {
         return;
     }
 
-    let se_ty = Ty::new_fn_ptr(
-        tcx,
-        expected_return_type.map_bound(|expected_return_type| {
-            tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
-        }),
-    );
+    let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+        [],
+        expected_return_type,
+        false,
+        hir::Unsafety::Normal,
+        Abi::Rust,
+    ));
 
-    require_same_types(
+    check_function_signature(
         tcx,
-        &ObligationCause::new(
+        ObligationCause::new(
             main_span,
             main_diagnostics_def_id,
             ObligationCauseCode::MainFunctionType,
         ),
-        param_env,
-        se_ty,
-        Ty::new_fn_ptr(tcx, main_fnsig),
+        main_def_id,
+        expected_sig,
     );
 }
 
@@ -212,7 +212,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                         });
                         error = true;
                     }
-                    if let hir::IsAsync::Async = sig.header.asyncness {
+                    if sig.header.asyncness.is_async() {
                         let span = tcx.def_span(it.owner_id);
                         tcx.sess.emit_err(errors::StartAsync { span: span });
                         error = true;
@@ -247,27 +247,23 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                 }
             }
 
-            let se_ty = Ty::new_fn_ptr(
-                tcx,
-                ty::Binder::dummy(tcx.mk_fn_sig(
-                    [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
-                    tcx.types.isize,
-                    false,
-                    hir::Unsafety::Normal,
-                    Abi::Rust,
-                )),
-            );
+            let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+                [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
+                tcx.types.isize,
+                false,
+                hir::Unsafety::Normal,
+                Abi::Rust,
+            ));
 
-            require_same_types(
+            check_function_signature(
                 tcx,
-                &ObligationCause::new(
+                ObligationCause::new(
                     start_span,
                     start_def_id,
                     ObligationCauseCode::StartFunctionType,
                 ),
-                ty::ParamEnv::empty(), // start should not have any where bounds.
-                se_ty,
-                Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).instantiate_identity()),
+                start_def_id.into(),
+                expected_sig,
             );
         }
         _ => {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index f89e2e5c25b..444103ffe8f 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -1,11 +1,11 @@
 //! Type-checking for the rust-intrinsic and platform-intrinsic
 //! intrinsics that the compiler exposes.
 
+use crate::check::check_function_signature;
 use crate::errors::{
     UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
     WrongNumberOfGenericArgumentsToIntrinsic,
 };
-use crate::require_same_types;
 
 use hir::def_id::DefId;
 use rustc_errors::{struct_span_err, DiagnosticMessage};
@@ -53,15 +53,12 @@ fn equate_intrinsic_type<'tcx>(
         && gen_count_ok(own_counts.types, n_tps, "type")
         && gen_count_ok(own_counts.consts, 0, "const")
     {
-        let fty = Ty::new_fn_ptr(tcx, sig);
         let it_def_id = it.owner_id.def_id;
-        let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType);
-        require_same_types(
+        check_function_signature(
             tcx,
-            &cause,
-            ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env?
-            Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).instantiate_identity()),
-            fty,
+            ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType),
+            it_def_id.into(),
+            sig,
         );
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index d8331661366..0cf3cee66b5 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -73,23 +73,31 @@ pub mod wfcheck;
 
 pub use check::check_abi;
 
+use std::num::NonZeroU32;
+
 use check::check_mod_item_types;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::BitSet;
+use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{self, TyCtxtInferExt as _};
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::query::Providers;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_session::parse::feature_err;
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, BytePos, Span, Symbol};
+use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use std::num::NonZeroU32;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::errors;
 use crate::require_c_abi_if_c_variadic;
@@ -546,3 +554,79 @@ fn bad_non_zero_sized_fields<'tcx>(
 pub fn potentially_plural_count(count: usize, word: &str) -> String {
     format!("{} {}{}", count, word, pluralize!(count))
 }
+
+pub fn check_function_signature<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mut cause: ObligationCause<'tcx>,
+    fn_id: DefId,
+    expected_sig: ty::PolyFnSig<'tcx>,
+) {
+    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
+
+    let param_env = ty::ParamEnv::empty();
+
+    let infcx = &tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
+
+    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
+
+    let norm_cause = ObligationCause::misc(cause.span, local_id);
+    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
+
+    let expected_ty = Ty::new_fn_ptr(tcx, expected_sig);
+    let actual_ty = Ty::new_fn_ptr(tcx, actual_sig);
+
+    match ocx.eq(&cause, param_env, expected_ty, actual_ty) {
+        Ok(()) => {
+            let errors = ocx.select_all_or_error();
+            if !errors.is_empty() {
+                infcx.err_ctxt().report_fulfillment_errors(&errors);
+                return;
+            }
+        }
+        Err(err) => {
+            let err_ctxt = infcx.err_ctxt();
+            if fn_id.is_local() {
+                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
+            }
+            let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
+            let mut diag = tcx.sess.create_err(failure_code);
+            err_ctxt.note_type_err(
+                &mut diag,
+                &cause,
+                None,
+                Some(infer::ValuePairs::Sigs(ExpectedFound {
+                    expected: tcx.liberate_late_bound_regions(fn_id, expected_sig),
+                    found: tcx.liberate_late_bound_regions(fn_id, actual_sig),
+                })),
+                err,
+                false,
+                false,
+            );
+            diag.emit();
+            return;
+        }
+    }
+
+    let outlives_env = OutlivesEnvironment::new(param_env);
+    let _ = ocx.resolve_regions_and_report_errors(local_id, &outlives_env);
+
+    fn extract_span_for_error_reporting<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        err: TypeError<'_>,
+        cause: &ObligationCause<'tcx>,
+        fn_id: LocalDefId,
+    ) -> rustc_span::Span {
+        let mut args = {
+            let node = tcx.hir().expect_owner(fn_id);
+            let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
+            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
+        };
+
+        match err {
+            TypeError::ArgumentMutability(i)
+            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
+            _ => cause.span(),
+        }
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 6869c869603..a39cfd7b6e1 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1213,7 +1213,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
                         && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
                         && param.is_elided_lifetime()
-                        && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
+                        && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
                         && !self.tcx.features().anonymous_lifetime_in_impl_trait
                     {
                         let mut diag =  rustc_session::parse::feature_err(
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 957a6bb3481..0544c5ca866 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -1,7 +1,7 @@
 use rustc_errors::StashKey;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem};
+use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::DUMMY_SP;
@@ -74,9 +74,14 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
 
         hidden.ty
     } else {
+        let mut parent_def_id = def_id;
+        while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
+            // Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
+            parent_def_id = tcx.local_parent(parent_def_id);
+        }
         let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
-            name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
+            name: tcx.item_name(parent_def_id.to_def_id()),
             what: match tcx.hir().get(scope) {
                 _ if scope == hir::CRATE_HIR_ID => "module",
                 Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index ef788935efb..03963925d3d 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -99,7 +99,6 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_fluent_macro::fluent_messages;
 use rustc_hir as hir;
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::middle;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -107,8 +106,7 @@ use rustc_middle::util;
 use rustc_session::parse::feature_err;
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
+use rustc_trait_selection::traits;
 
 use astconv::{AstConv, OnlySelfBounds};
 use bounds::Bounds;
@@ -151,28 +149,6 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
     tcx.sess.emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions });
 }
 
-fn require_same_types<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    cause: &ObligationCause<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    expected: Ty<'tcx>,
-    actual: Ty<'tcx>,
-) {
-    let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
-    match ocx.eq(cause, param_env, expected, actual) {
-        Ok(()) => {
-            let errors = ocx.select_all_or_error();
-            if !errors.is_empty() {
-                infcx.err_ctxt().report_fulfillment_errors(&errors);
-            }
-        }
-        Err(err) => {
-            infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
-        }
-    }
-}
-
 pub fn provide(providers: &mut Providers) {
     collect::provide(providers);
     coherence::provide(providers);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 89efdc269c4..8587b009f25 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -2304,7 +2304,7 @@ impl<'a> State<'a> {
 
         match header.asyncness {
             hir::IsAsync::NotAsync => {}
-            hir::IsAsync::Async => self.word_nbsp("async"),
+            hir::IsAsync::Async(_) => self.word_nbsp("async"),
         }
 
         self.print_unsafety(header.unsafety);
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 921a5f5154a..9950a226333 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -83,16 +83,6 @@ hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*cons
 
 hir_typeck_invalid_callee = expected function, found {$ty}
 
-hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
-hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
-hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
-
-hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
-    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
-
-hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
-    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
-
 hir_typeck_lossy_provenance_int2ptr =
     strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
     .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index b39919ece71..f2c58ee2702 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -788,7 +788,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let effect = match const_context {
             _ if host_always_on => tcx.consts.true_,
-            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
+            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => {
+                tcx.consts.false_
+            }
             Some(hir::ConstContext::ConstFn) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, context);
                 args.host_effect_param().expect("ConstContext::Maybe must have host effect param")
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 1fc1e5aca2b..041cc1abd54 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -1,7 +1,6 @@
+use std::cell::RefCell;
+
 use crate::coercion::CoerceMany;
-use crate::errors::{
-    LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy,
-};
 use crate::gather_locals::GatherLocalsVisitor;
 use crate::FnCtxt;
 use crate::GeneratorTypes;
@@ -9,14 +8,15 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir_analysis::check::fn_maybe_err;
+use rustc_hir_analysis::check::{check_function_signature, fn_maybe_err};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
+use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
-use std::cell::RefCell;
+use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 
 /// Helper used for fns and closures. Does the grungy work of checking a function
 /// body and returns the function context used for that purpose, since in the case of a fn item
@@ -166,52 +166,17 @@ pub(super) fn check_fn<'a, 'tcx>(
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
         && panic_impl_did == fn_def_id.to_def_id()
     {
-        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
+        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig);
     }
 
     if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() {
-        check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
+        check_lang_start_fn(tcx, fn_sig, fn_def_id);
     }
 
     gen_ty
 }
 
-fn check_panic_info_fn(
-    tcx: TyCtxt<'_>,
-    fn_id: LocalDefId,
-    fn_sig: ty::FnSig<'_>,
-    decl: &hir::FnDecl<'_>,
-    declared_ret_ty: Ty<'_>,
-) {
-    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
-        tcx.sess.err("language item required, but not found: `panic_info`");
-        return;
-    };
-
-    if *declared_ret_ty.kind() != ty::Never {
-        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
-    }
-
-    let inputs = fn_sig.inputs();
-    if inputs.len() != 1 {
-        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
-        return;
-    }
-
-    let arg_is_panic_info = match *inputs[0].kind() {
-        ty::Ref(region, ty, mutbl) => match *ty.kind() {
-            ty::Adt(ref adt, _) => {
-                adt.did() == panic_info_did && mutbl.is_not() && !region.is_static()
-            }
-            _ => false,
-        },
-        _ => false,
-    };
-
-    if !arg_is_panic_info {
-        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-    }
-
+fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) {
     let DefKind::Fn = tcx.def_kind(fn_id) else {
         let span = tcx.def_span(fn_id);
         tcx.sess.span_err(span, "should be a function");
@@ -227,125 +192,87 @@ fn check_panic_info_fn(
         let span = tcx.def_span(fn_id);
         tcx.sess.span_err(span, "should have no const parameters");
     }
-}
-
-fn check_lang_start_fn<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    fn_sig: ty::FnSig<'tcx>,
-    decl: &'tcx hir::FnDecl<'tcx>,
-    def_id: LocalDefId,
-) {
-    let inputs = fn_sig.inputs();
-
-    let arg_count = inputs.len();
-    if arg_count != 4 {
-        tcx.sess.emit_err(LangStartIncorrectNumberArgs {
-            params_span: tcx.def_span(def_id),
-            found_param_count: arg_count,
-        });
-    }
 
-    // only check args if they should exist by checking the count
-    // note: this does not handle args being shifted or their order swapped very nicely
-    // but it's a lang item, users shouldn't frequently encounter this
-
-    // first arg is `main: fn() -> T`
-    if let Some(&main_arg) = inputs.get(0) {
-        // make a Ty for the generic on the fn for diagnostics
-        // FIXME: make the lang item generic checks check for the right generic *kind*
-        // for example `start`'s generic should be a type parameter
-        let generics = tcx.generics_of(def_id);
-        let fn_generic = generics.param_at(0, tcx);
-        let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
-        let expected_fn_sig =
-            tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
-        let expected_ty = Ty::new_fn_ptr(tcx, Binder::dummy(expected_fn_sig));
-
-        // we emit the same error to suggest changing the arg no matter what's wrong with the arg
-        let emit_main_fn_arg_err = || {
-            tcx.sess.emit_err(LangStartIncorrectParam {
-                param_span: decl.inputs[0].span,
-                param_num: 1,
-                expected_ty: expected_ty,
-                found_ty: main_arg,
-            });
-        };
-
-        if let ty::FnPtr(main_fn_sig) = main_arg.kind() {
-            let main_fn_inputs = main_fn_sig.inputs();
-            if main_fn_inputs.iter().count() != 0 {
-                emit_main_fn_arg_err();
-            }
-
-            let output = main_fn_sig.output();
-            output.map_bound(|ret_ty| {
-                // if the output ty is a generic, it's probably the right one
-                if !matches!(ret_ty.kind(), ty::Param(_)) {
-                    emit_main_fn_arg_err();
-                }
-            });
-        } else {
-            emit_main_fn_arg_err();
-        }
-    }
-
-    // second arg is isize
-    if let Some(&argc_arg) = inputs.get(1) {
-        if argc_arg != tcx.types.isize {
-            tcx.sess.emit_err(LangStartIncorrectParam {
-                param_span: decl.inputs[1].span,
-                param_num: 2,
-                expected_ty: tcx.types.isize,
-                found_ty: argc_arg,
-            });
-        }
-    }
-
-    // third arg is `*const *const u8`
-    if let Some(&argv_arg) = inputs.get(2) {
-        let mut argv_is_okay = false;
-        if let ty::RawPtr(outer_ptr) = argv_arg.kind() {
-            if outer_ptr.mutbl.is_not() {
-                if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() {
-                    if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 {
-                        argv_is_okay = true;
-                    }
-                }
-            }
-        }
-
-        if !argv_is_okay {
-            let inner_ptr_ty =
-                Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
-            let expected_ty =
-                Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
-            tcx.sess.emit_err(LangStartIncorrectParam {
-                param_span: decl.inputs[2].span,
-                param_num: 3,
-                expected_ty,
-                found_ty: argv_arg,
-            });
-        }
-    }
+    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+        tcx.sess.err("language item required, but not found: `panic_info`");
+        return;
+    };
 
-    // fourth arg is `sigpipe: u8`
-    if let Some(&sigpipe_arg) = inputs.get(3) {
-        if sigpipe_arg != tcx.types.u8 {
-            tcx.sess.emit_err(LangStartIncorrectParam {
-                param_span: decl.inputs[3].span,
-                param_num: 4,
-                expected_ty: tcx.types.u8,
-                found_ty: sigpipe_arg,
-            });
-        }
-    }
+    // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !`
+    let panic_info_ty = tcx.type_of(panic_info_did).instantiate(
+        tcx,
+        &[ty::GenericArg::from(ty::Region::new_late_bound(
+            tcx,
+            ty::INNERMOST,
+            ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon(None) },
+        ))],
+    );
+    let panic_info_ref_ty = Ty::new_imm_ref(
+        tcx,
+        ty::Region::new_late_bound(
+            tcx,
+            ty::INNERMOST,
+            ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) },
+        ),
+        panic_info_ty,
+    );
+
+    let bounds = tcx.mk_bound_variable_kinds(&[
+        ty::BoundVariableKind::Region(ty::BrAnon(None)),
+        ty::BoundVariableKind::Region(ty::BrAnon(None)),
+    ]);
+    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),
+        bounds,
+    );
+
+    check_function_signature(
+        tcx,
+        ObligationCause::new(
+            tcx.def_span(fn_id),
+            fn_id,
+            ObligationCauseCode::LangFunctionType(sym::panic_impl),
+        ),
+        fn_id.into(),
+        expected_sig,
+    );
+}
 
-    // output type is isize
-    if fn_sig.output() != tcx.types.isize {
-        tcx.sess.emit_err(LangStartIncorrectRetTy {
-            ret_span: decl.output.span(),
-            expected_ty: tcx.types.isize,
-            found_ty: fn_sig.output(),
-        });
-    }
+fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: LocalDefId) {
+    // build type `fn(main: fn() -> T, argc: isize, argv: *const *const u8, sigpipe: u8)`
+
+    // make a Ty for the generic on the fn for diagnostics
+    // FIXME: make the lang item generic checks check for the right generic *kind*
+    // for example `start`'s generic should be a type parameter
+    let generics = tcx.generics_of(def_id);
+    let fn_generic = generics.param_at(0, tcx);
+    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)),
+    );
+
+    let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+        [
+            main_fn_ty,
+            tcx.types.isize,
+            Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8)),
+            tcx.types.u8,
+        ],
+        tcx.types.isize,
+        false,
+        fn_sig.unsafety,
+        Abi::Rust,
+    ));
+
+    check_function_signature(
+        tcx,
+        ObligationCause::new(
+            tcx.def_span(def_id),
+            def_id,
+            ObligationCauseCode::LangFunctionType(sym::start),
+        ),
+        def_id.into(),
+        expected_sig,
+    );
 }
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 7152585d440..1526988fbd9 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -236,39 +236,6 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
     }
 }
 
-#[derive(Diagnostic)]
-#[diag(hir_typeck_lang_start_incorrect_number_params)]
-#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)]
-#[note(hir_typeck_lang_start_expected_sig_note)]
-pub struct LangStartIncorrectNumberArgs {
-    #[primary_span]
-    pub params_span: Span,
-    pub found_param_count: usize,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_typeck_lang_start_incorrect_param)]
-pub struct LangStartIncorrectParam<'tcx> {
-    #[primary_span]
-    #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
-    pub param_span: Span,
-
-    pub param_num: usize,
-    pub expected_ty: Ty<'tcx>,
-    pub found_ty: Ty<'tcx>,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_typeck_lang_start_incorrect_ret_ty)]
-pub struct LangStartIncorrectRetTy<'tcx> {
-    #[primary_span]
-    #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
-    pub ret_span: Span,
-
-    pub expected_ty: Ty<'tcx>,
-    pub found_ty: Ty<'tcx>,
-}
-
 #[derive(LintDiagnostic)]
 #[diag(hir_typeck_lossy_provenance_int2ptr)]
 #[help]
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 70d1dad8a6f..4ad14ce3059 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -525,8 +525,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
         };
 
-        if let ty::FnDef(did, ..) = *ty.kind() {
+        if let ty::FnDef(did, callee_args) = *ty.kind() {
             let fn_sig = ty.fn_sig(tcx);
+
+            // HACK: whenever we get a FnDef in a non-const context, enforce effects to get the
+            // default `host = true` to avoid inference errors later.
+            if tcx.hir().body_const_context(self.body_id).is_none() {
+                self.enforce_context_effects(expr.hir_id, qpath.span(), did, callee_args);
+            }
             if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic
                 && tcx.item_name(did) == sym::transmute
             {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 4def7867384..37ea94d821e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -273,11 +273,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             //
             // This check is here because there is currently no way to express a trait bound for `FnDef` types only.
             if is_const_eval_select && (1..=2).contains(&idx) {
-                if let ty::FnDef(def_id, _) = checked_ty.kind() {
-                    if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) {
-                        self.tcx
-                            .sess
-                            .emit_err(errors::ConstSelectMustBeConst { span: provided_arg.span });
+                if let ty::FnDef(def_id, args) = *checked_ty.kind() {
+                    if idx == 1 {
+                        if !self.tcx.is_const_fn_raw(def_id) {
+                            self.tcx.sess.emit_err(errors::ConstSelectMustBeConst {
+                                span: provided_arg.span,
+                            });
+                        } else {
+                            self.enforce_context_effects(
+                                provided_arg.hir_id,
+                                provided_arg.span,
+                                def_id,
+                                args,
+                            )
+                        }
                     }
                 } else {
                     self.tcx.sess.emit_err(errors::ConstSelectMustBeFn {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index d2a53ee8b5e..41f815a812a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -987,10 +987,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let bound_vars = self.tcx.late_bound_vars(fn_id);
             let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
             let ty = match self.tcx.asyncness(fn_id.owner) {
-                hir::IsAsync::Async => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+                ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
                     span_bug!(fn_decl.output.span(), "failed to get output type of async function")
                 }),
-                hir::IsAsync::NotAsync => ty,
+                ty::Asyncness::No => ty,
             };
             let ty = self.normalize(expr.span, ty);
             if self.can_coerce(found, ty) {
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 603681bbc99..2fe41c1197f 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         // Type only exists for constants and statics, not functions.
         match self.tcx.hir().body_owner_kind(item_def_id) {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
+            hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => {
                 let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id);
                 wbcx.visit_node_id(body.value.span, item_hir_id);
             }
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 5e7ae3ecdb8..1b160eca92d 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -42,7 +42,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::dep_graph::{
-    DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
+    dep_kinds, DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
 };
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
@@ -129,7 +129,7 @@ impl<'tcx> IfThisChanged<'tcx> {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
                     None => {
-                        DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner)
+                        DepNode::from_def_path_hash(self.tcx, def_path_hash, dep_kinds::hir_owner)
                     }
                     Some(n) => {
                         match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 8d67f692568..25e694fa1c1 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -3,7 +3,7 @@
 use crate::errors;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::unord::UnordMap;
-use rustc_middle::dep_graph::{SerializedDepGraph, WorkProductMap};
+use rustc_middle::dep_graph::{DepsType, SerializedDepGraph, WorkProductMap};
 use rustc_middle::query::on_disk_cache::OnDiskCache;
 use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::Decodable;
@@ -208,7 +208,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
                     return LoadResult::DataOutOfDate;
                 }
 
-                let dep_graph = SerializedDepGraph::decode(&mut decoder);
+                let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
 
                 LoadResult::Ok { data: (dep_graph, prev_work_products) }
             }
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index 4d0e7706367..46558997f72 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -198,6 +198,10 @@ infer_nothing = {""}
 infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
 infer_oc_closure_selfref = closure/generator type that references itself
 infer_oc_const_compat = const not compatible with trait
+infer_oc_fn_lang_correct_type = {$lang_item_name ->
+        [panic_impl] `#[panic_handler]`
+        *[lang_item_name] lang item `{$lang_item_name}`
+    } function has wrong type
 infer_oc_fn_main_correct_type = `main` function has wrong type
 infer_oc_fn_start_correct_type = `#[start]` function has wrong type
 infer_oc_generic = mismatched types
@@ -337,6 +341,7 @@ infer_subtype = ...so that the {$requirement ->
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
     [fn_start_correct_type] `#[start]` function has the correct type
+    [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
     *[other] types are compatible
@@ -350,6 +355,7 @@ infer_subtype_2 = ...so that {$requirement ->
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
     [fn_start_correct_type] `#[start]` function has the correct type
+    [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
     *[other] types are compatible
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index a7e045e1e89..38910e45ecc 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1463,6 +1463,14 @@ pub enum ObligationCauseFailureCode {
         #[subdiagnostic]
         subdiags: Vec<TypeErrorAdditionalDiags>,
     },
+    #[diag(infer_oc_fn_lang_correct_type, code = "E0308")]
+    FnLangCorrectType {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+        lang_item_name: Symbol,
+    },
     #[diag(infer_oc_intrinsic_correct_type, code = "E0308")]
     IntrinsicCorrectType {
         #[primary_span]
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b8701d3d3ef..1beb13cb94c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2927,6 +2927,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
             | IfExpression { .. }
             | LetElse
             | StartFunctionType
+            | LangFunctionType(_)
             | IntrinsicType
             | MethodReceiver => Error0308,
 
@@ -2971,6 +2972,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
             LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
             MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
             StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
+            &LangFunctionType(lang_item_name) => {
+                ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
+            }
             IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags },
             MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
 
@@ -3006,6 +3010,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
             IfExpressionWithNoElse => "`if` missing an `else` returns `()`",
             MainFunctionType => "`main` function has the correct type",
             StartFunctionType => "`#[start]` function has the correct type",
+            LangFunctionType(_) => "lang item function has the correct type",
             IntrinsicType => "intrinsic has the correct type",
             MethodReceiver => "method receiver has the correct type",
             _ => "types are compatible",
@@ -3028,6 +3033,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
             IfExpressionWithNoElse => "no_else",
             MainFunctionType => "fn_main_correct_type",
             StartFunctionType => "fn_start_correct_type",
+            LangFunctionType(_) => "fn_lang_correct_type",
             IntrinsicType => "intrinsic_correct_type",
             MethodReceiver => "method_correct_type",
             _ => "other",
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index bc6d7c20997..45b1aeb4a5c 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -10,8 +10,10 @@
 //! origin crate when the `TyCtxt` is not present in TLS.
 
 use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
-use rustc_middle::dep_graph::TaskDepsRef;
+use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
 use rustc_middle::ty::tls;
+use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
+use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode};
 use std::fmt;
 
 fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
@@ -59,10 +61,49 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
     write!(f, ")")
 }
 
+/// This is a callback from `rustc_query_system` as it cannot access the implicit state
+/// in `rustc_middle` otherwise.
+pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    tls::with_opt(|opt_tcx| {
+        if let Some(tcx) = opt_tcx {
+            write!(f, "{}", tcx.dep_kind_info(kind).name)
+        } else {
+            default_dep_kind_debug(kind, f)
+        }
+    })
+}
+
+/// This is a callback from `rustc_query_system` as it cannot access the implicit state
+/// in `rustc_middle` otherwise.
+pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    write!(f, "{:?}(", node.kind)?;
+
+    tls::with_opt(|opt_tcx| {
+        if let Some(tcx) = opt_tcx {
+            if let Some(def_id) = node.extract_def_id(tcx) {
+                write!(f, "{}", tcx.def_path_debug_str(def_id))?;
+            } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) {
+                write!(f, "{s}")?;
+            } else {
+                write!(f, "{}", node.hash)?;
+            }
+        } else {
+            write!(f, "{}", node.hash)?;
+        }
+        Ok(())
+    })?;
+
+    write!(f, ")")
+}
+
 /// Sets up the callbacks in prior crates which we want to refer to the
 /// TyCtxt in.
 pub fn setup_callbacks() {
     rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
     rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
+    rustc_query_system::dep_graph::dep_node::DEP_KIND_DEBUG
+        .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
+    rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
+        .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
     TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
 }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index d0967ba5644..814991cd8c9 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -34,8 +34,8 @@ declare_lint! {
     Warn,
     "detects calling `into_iter` on arrays in Rust 2015 and 2018",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
         reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
     };
 }
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index de228bdb850..4f6b79d9aee 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -41,7 +41,6 @@ use crate::{
     },
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
 };
-use hir::IsAsync;
 use rustc_ast::attr;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
@@ -845,8 +844,8 @@ declare_lint! {
     Warn,
     "detects anonymous parameters",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
+        reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
     };
 }
 
@@ -1294,7 +1293,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
         span: Span,
         def_id: LocalDefId,
     ) {
-        if fn_kind.asyncness() == IsAsync::Async
+        if fn_kind.asyncness().is_async()
             && !cx.tcx.features().async_fn_track_caller
             // Now, check if the function has the `#[track_caller]` attribute
             && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
@@ -1670,8 +1669,8 @@ declare_lint! {
     Warn,
     "`...` range patterns are deprecated",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
     };
 }
 
@@ -1805,8 +1804,8 @@ declare_lint! {
     Allow,
     "detects edition keywords being used as an identifier",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
+        reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
     };
 }
 
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 7a336a8f694..460d54739a2 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1315,6 +1315,54 @@ impl<'tcx> LateContext<'tcx> {
                 tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
             })
     }
+
+    /// If the given expression is a local binding, find the initializer expression.
+    /// If that initializer expression is another local or **outside** (`const`/`static`)
+    /// binding, find its initializer again.
+    ///
+    /// This process repeats as long as possible (but usually no more than once).
+    /// Type-check adjustments are not taken in account in this function.
+    ///
+    /// Examples:
+    /// ```
+    /// const ABC: i32 = 1;
+    /// //               ^ output
+    /// let def = ABC;
+    /// dbg!(def);
+    /// //   ^^^ input
+    ///
+    /// // or...
+    /// let abc = 1;
+    /// let def = abc + 2;
+    /// //        ^^^^^^^ output
+    /// dbg!(def);
+    /// //   ^^^ input
+    /// ```
+    pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
+        expr = expr.peel_blocks();
+
+        while let hir::ExprKind::Path(ref qpath) = expr.kind
+            && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
+                Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id),
+                Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id),
+                _ => None,
+            }
+            && let Some(init) = match parent_node {
+                hir::Node::Expr(expr) => Some(expr),
+                hir::Node::Local(hir::Local { init, .. }) => *init,
+                hir::Node::Item(item) => match item.kind {
+                    hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
+                        Some(self.tcx.hir().body(body_id).value)
+                    }
+                    _ => None
+                }
+                _ => None
+            }
+        {
+            expr = init.peel_blocks();
+        }
+        expr
+    }
 }
 
 impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index 851c6493daf..9be2edf8453 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -5,6 +5,7 @@ use crate::{
 
 use rustc_hir as hir;
 use rustc_middle::{traits::util::supertraits, ty};
+use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_span::sym;
 
 declare_lint! {
@@ -48,6 +49,7 @@ declare_lint! {
     Warn,
     "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
     };
 }
diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs
index 3291286ad67..1841e7c85a8 100644
--- a/compiler/rustc_lint/src/invalid_from_utf8.rs
+++ b/compiler/rustc_lint/src/invalid_from_utf8.rs
@@ -1,6 +1,6 @@
 use std::str::Utf8Error;
 
-use rustc_ast::{BorrowKind, LitKind};
+use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_span::source_map::Spanned;
 use rustc_span::sym;
@@ -11,7 +11,7 @@ use crate::{LateContext, LateLintPass, LintContext};
 declare_lint! {
     /// The `invalid_from_utf8_unchecked` lint checks for calls to
     /// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut`
-    /// with an invalid UTF-8 literal.
+    /// with a known invalid UTF-8 value.
     ///
     /// ### Example
     ///
@@ -36,7 +36,7 @@ declare_lint! {
 declare_lint! {
     /// The `invalid_from_utf8` lint checks for calls to
     /// `std::str::from_utf8` and `std::str::from_utf8_mut`
-    /// with an invalid UTF-8 literal.
+    /// with a known invalid UTF-8 value.
     ///
     /// ### Example
     ///
@@ -67,8 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
             && [sym::str_from_utf8, sym::str_from_utf8_mut,
                 sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item)
         {
-            let lint = |utf8_error: Utf8Error| {
-                let label = arg.span;
+            let lint = |label, utf8_error: Utf8Error| {
                 let method = diag_item.as_str().strip_prefix("str_").unwrap();
                 let method = format!("std::str::{method}");
                 let valid_up_to = utf8_error.valid_up_to();
@@ -78,22 +77,26 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
                     if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 },
                     expr.span,
                     if is_unchecked_variant {
-                        InvalidFromUtf8Diag::Unchecked { method,  valid_up_to, label }
+                        InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label }
                     } else {
-                        InvalidFromUtf8Diag::Checked { method,  valid_up_to, label }
+                        InvalidFromUtf8Diag::Checked { method, valid_up_to, label }
                     }
                 )
             };
 
-            match &arg.kind {
+            let mut init = cx.expr_or_init(arg);
+            while let ExprKind::AddrOf(.., inner) = init.kind {
+                init = cx.expr_or_init(inner);
+            }
+            match init.kind {
                 ExprKind::Lit(Spanned { node: lit, .. }) => {
                     if let LitKind::ByteStr(bytes, _) = &lit
                         && let Err(utf8_error) = std::str::from_utf8(bytes)
                     {
-                        lint(utf8_error);
+                        lint(init.span, utf8_error);
                     }
                 },
-                ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => {
+                ExprKind::Array(args) => {
                     let elements = args.iter().map(|e|{
                         match &e.kind {
                             ExprKind::Lit(Spanned { node: lit, .. }) => match lit {
@@ -108,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
                     if let Some(elements) = elements
                         && let Err(utf8_error) = std::str::from_utf8(&elements)
                     {
-                        lint(utf8_error);
+                        lint(init.span, utf8_error);
                     }
                 }
                 _ => {}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 860366fdd61..1951db49e91 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -39,6 +39,7 @@ declare_lint! {
     Warn,
     "applying forbid to lint-groups",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #81670 <https://github.com/rust-lang/rust/issues/81670>",
     };
 }
@@ -74,6 +75,7 @@ declare_lint! {
     Deny,
     "ill-formed attribute inputs that were previously accepted and used in practice",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
     };
     crate_level_only
@@ -110,6 +112,7 @@ declare_lint! {
     Deny,
     "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #68585 <https://github.com/rust-lang/rust/issues/68585>",
     };
 }
@@ -1016,8 +1019,8 @@ declare_lint! {
     Deny,
     "raw pointers must be aligned before dereferencing",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -1096,6 +1099,7 @@ declare_lint! {
     Deny,
     "detect public re-exports of private extern crates",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
     };
 }
@@ -1125,6 +1129,7 @@ declare_lint! {
     Deny,
     "type parameter default erroneously allowed in invalid location",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
     };
 }
@@ -1267,6 +1272,7 @@ declare_lint! {
     Deny,
     "patterns in functions without body were erroneously allowed",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
     };
 }
@@ -1310,6 +1316,7 @@ declare_lint! {
     Deny,
     "detects missing fragment specifiers in unused `macro_rules!` patterns",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
     };
 }
@@ -1351,6 +1358,7 @@ declare_lint! {
     Warn,
     "detects generic lifetime arguments in path segments with late bound lifetime parameters",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
     };
 }
@@ -1386,8 +1394,8 @@ declare_lint! {
     Deny,
     "trait-object types were treated as different depending on marker-trait order",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -1426,6 +1434,7 @@ declare_lint! {
     Warn,
     "distinct impls distinguished only by the leak-check code",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #56105 <https://github.com/rust-lang/rust/issues/56105>",
     };
 }
@@ -1617,8 +1626,8 @@ declare_lint! {
     Warn,
     "raw pointer to an inference variable",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
+        reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
     };
 }
 
@@ -1685,8 +1694,8 @@ declare_lint! {
     Warn,
     "suggest using `dyn Trait` for trait objects",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
     };
 }
 
@@ -1740,8 +1749,8 @@ declare_lint! {
     "fully qualified paths that start with a module name \
      instead of `crate`, `self`, or an extern crate name",
      @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
+        reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>",
      };
 }
 
@@ -1789,6 +1798,7 @@ declare_lint! {
     Warn,
     "floating-point literals cannot be used in patterns",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
     };
 }
@@ -1939,6 +1949,7 @@ declare_lint! {
     Warn,
     "checks the object safety of where clauses",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>",
     };
 }
@@ -2005,8 +2016,8 @@ declare_lint! {
     Deny,
     "detects proc macro derives using inaccessible names from parent modules",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -2108,6 +2119,7 @@ declare_lint! {
     "macro-expanded `macro_export` macros from the current crate \
      cannot be referred to by absolute paths",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
     };
     crate_level_only
@@ -2199,6 +2211,7 @@ declare_lint! {
     Warn,
     "constant used in pattern contains value of non-structural-match type in a field or a variant",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
     };
 }
@@ -2253,6 +2266,7 @@ declare_lint! {
     Allow,
     "pointers are not structural-match",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #62411 <https://github.com/rust-lang/rust/issues/70861>",
     };
 }
@@ -2291,6 +2305,7 @@ declare_lint! {
     "constant used in pattern of non-structural-match type and the constant's initializer \
     expression contains values of non-structural-match types",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #73448 <https://github.com/rust-lang/rust/issues/73448>",
     };
 }
@@ -2348,6 +2363,7 @@ declare_lint! {
     Deny,
     "ambiguous associated items",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>",
     };
 }
@@ -2389,6 +2405,7 @@ declare_lint! {
     Deny,
     "a feature gate that doesn't break dependent crates",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>",
     };
 }
@@ -2617,8 +2634,8 @@ declare_lint! {
     Deny,
     "a C-like enum implementing Drop is cast",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -2747,6 +2764,7 @@ declare_lint! {
     Warn,
     "detects a generic constant is used in a type without a emitting a warning",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #76200 <https://github.com/rust-lang/rust/issues/76200>",
     };
 }
@@ -2805,6 +2823,7 @@ declare_lint! {
     Warn,
     "uninhabited static",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #74840 <https://github.com/rust-lang/rust/issues/74840>",
     };
 }
@@ -2975,8 +2994,8 @@ declare_lint! {
     Warn,
     "trailing semicolon in macro body used as expression",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -3022,6 +3041,7 @@ declare_lint! {
     Warn,
     "detects derive helper attributes that are used before they are introduced",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #79202 <https://github.com/rust-lang/rust/issues/79202>",
     };
 }
@@ -3090,6 +3110,7 @@ declare_lint! {
     Deny,
     "detects usage of `#![cfg_attr(..., crate_type/crate_name = \"...\")]`",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #91632 <https://github.com/rust-lang/rust/issues/91632>",
     };
 }
@@ -3181,6 +3202,7 @@ declare_lint! {
     Warn,
     "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>",
     };
 }
@@ -3231,6 +3253,7 @@ declare_lint! {
     Warn,
     "unstable syntax can change at any point in the future, causing a hard error!",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #65860 <https://github.com/rust-lang/rust/issues/65860>",
     };
 }
@@ -3662,6 +3685,7 @@ declare_lint! {
     Warn,
     "detects invalid `#[doc(...)]` attributes",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #82730 <https://github.com/rust-lang/rust/issues/82730>",
     };
 }
@@ -3708,8 +3732,8 @@ declare_lint! {
     Deny,
     "detects usage of old versions of certain proc-macro crates",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -3747,8 +3771,8 @@ declare_lint! {
     Allow,
     "detects usage of old versions of or-patterns",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>",
     };
 }
 
@@ -3796,8 +3820,8 @@ declare_lint! {
     "detects the usage of trait methods which are ambiguous with traits added to the \
         prelude in future editions",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>",
     };
 }
 
@@ -3833,8 +3857,8 @@ declare_lint! {
     Allow,
     "identifiers that will be parsed as a prefix in Rust 2021",
     @future_incompatible = FutureIncompatibleInfo {
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>",
         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>",
     };
     crate_level_only
 }
@@ -3881,6 +3905,7 @@ declare_lint! {
     Warn,
     "use of unsupported calling convention",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #87678 <https://github.com/rust-lang/rust/issues/87678>",
     };
 }
@@ -4221,8 +4246,8 @@ declare_lint! {
     Deny,
     "impl method assumes more implied bounds than its corresponding trait method",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -4253,8 +4278,8 @@ declare_lint! {
     Warn,
     "`[u8]` or `str` used in a packed struct with `derive`",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
     report_in_external_macro
 }
@@ -4415,6 +4440,7 @@ declare_lint! {
     "impls that are not considered to overlap may be considered to \
     overlap in the future",
     @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #114040 <https://github.com/rust-lang/rust/issues/114040>",
     };
 }
@@ -4483,7 +4509,7 @@ declare_lint! {
     Warn,
     "detects certain glob imports that require reporting an ambiguity error",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseError,
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #114095 <https://github.com/rust-lang/rust/issues/114095>",
     };
 }
@@ -4568,7 +4594,7 @@ declare_lint! {
     Warn,
     "elided lifetimes cannot be used in associated constants in impls",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseError,
+        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
         reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>",
     };
 }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index ef2f7940477..84e7ecb0b88 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -347,12 +347,18 @@ pub struct FutureIncompatibleInfo {
 /// The reason for future incompatibility
 #[derive(Copy, Clone, Debug)]
 pub enum FutureIncompatibilityReason {
-    /// This will be an error in a future release
-    /// for all editions
-    FutureReleaseError,
+    /// This will be an error in a future release for all editions
+    ///
+    /// This will *not* show up in cargo's future breakage report.
+    /// The warning will hence only be seen in local crates, not in dependencies.
+    FutureReleaseErrorDontReportInDeps,
     /// This will be an error in a future release, and
     /// Cargo should create a report even for dependencies
-    FutureReleaseErrorReportNow,
+    ///
+    /// This is the *only* reason that will make future incompatibility warnings show up in cargo's
+    /// reports. All other future incompatibility warnings are not visible when they occur in a
+    /// dependency.
+    FutureReleaseErrorReportInDeps,
     /// Code that changes meaning in some way in a
     /// future release.
     FutureReleaseSemanticsChange,
@@ -380,7 +386,7 @@ impl FutureIncompatibleInfo {
     pub const fn default_fields_for_macro() -> Self {
         FutureIncompatibleInfo {
             reference: "",
-            reason: FutureIncompatibilityReason::FutureReleaseError,
+            reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
             explain_reason: true,
         }
     }
@@ -718,7 +724,10 @@ macro_rules! declare_lint {
     );
     ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
      $(@feature_gate = $gate:expr;)?
-     $(@future_incompatible = FutureIncompatibleInfo { $($field:ident : $val:expr),* $(,)*  }; )?
+     $(@future_incompatible = FutureIncompatibleInfo {
+        reason: $reason:expr,
+        $($field:ident : $val:expr),* $(,)*
+     }; )?
      $(@edition $lint_edition:ident => $edition_level:ident;)?
      $($v:ident),*) => (
         $(#[$attr])*
@@ -730,6 +739,7 @@ macro_rules! declare_lint {
             $($v: true,)*
             $(feature_gate: Some($gate),)?
             $(future_incompatible: Some($crate::FutureIncompatibleInfo {
+                reason: $reason,
                 $($field: $val,)*
                 ..$crate::FutureIncompatibleInfo::default_fields_for_macro()
             }),)?
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index f964a8c76c0..e8c2fe5d178 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -126,8 +126,8 @@ macro_rules! provide_one {
             // External query providers call `crate_hash` in order to register a dependency
             // on the crate metadata. The exception is `crate_hash` itself, which obviously
             // doesn't need to do this (and can't, as it would cause a query cycle).
-            use rustc_middle::dep_graph::DepKind;
-            if DepKind::$name != DepKind::crate_hash && $tcx.dep_graph.is_fully_enabled() {
+            use rustc_middle::dep_graph::dep_kinds;
+            if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() {
                 $tcx.ensure().crate_hash($def_id.krate);
             }
 
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 71269779d42..f2875bb11b1 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -439,7 +439,7 @@ define_tables! {
     coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
     mir_const_qualif: Table<DefIndex, LazyValue<mir::ConstQualifs>>,
     rendered_const: Table<DefIndex, LazyValue<String>>,
-    asyncness: Table<DefIndex, hir::IsAsync>,
+    asyncness: Table<DefIndex, ty::Asyncness>,
     fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
     generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>,
     trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 35987072ed6..d105dab4814 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -205,9 +205,9 @@ fixed_size_enum! {
 }
 
 fixed_size_enum! {
-    hir::IsAsync {
-        ( NotAsync )
-        ( Async    )
+    ty::Asyncness {
+        ( Yes )
+        ( No  )
     }
 }
 
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 78a0f82db13..39d82c489d5 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -65,9 +65,9 @@ use rustc_hir::definitions::DefPathHash;
 use rustc_hir::{HirId, ItemLocalId, OwnerId};
 use rustc_query_system::dep_graph::FingerprintStyle;
 use rustc_span::symbol::Symbol;
-use std::hash::Hash;
 
-pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
+pub use rustc_query_system::dep_graph::dep_node::DepKind;
+pub use rustc_query_system::dep_graph::{DepContext, DepNode, DepNodeParams};
 
 macro_rules! define_dep_nodes {
     (
@@ -84,55 +84,39 @@ macro_rules! define_dep_nodes {
         // encoding. The derived Encodable/Decodable uses leb128 encoding which is
         // dense when only considering this enum. But DepKind is encoded in a larger
         // struct, and there we can take advantage of the unused bits in the u16.
-        #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
         #[allow(non_camel_case_types)]
-        #[repr(u16)]
-        pub enum DepKind {
+        #[repr(u16)] // Must be kept in sync with the inner type of `DepKind`.
+        enum DepKindDefs {
             $( $( #[$attr] )* $variant),*
         }
 
-        impl DepKind {
-            // This const implements two things: A bounds check so that we can decode
-            // a DepKind from a u16 with just one check, and a const check that the
-            // discriminants of the variants have been assigned consecutively from 0
-            // so that just the one comparison suffices to check that the u16 can be
-            // transmuted to a DepKind.
-            pub const VARIANTS: u16 = {
-                let deps: &[DepKind] = &[$(DepKind::$variant,)*];
-                let mut i = 0;
-                while i < deps.len() {
-                    if i as u16 != deps[i] as u16 {
-                        panic!();
-                    }
-                    i += 1;
-                }
-                deps.len() as u16
-            };
-        }
+        #[allow(non_upper_case_globals)]
+        pub mod dep_kinds {
+            use super::*;
 
-        impl<S: rustc_serialize::Encoder> rustc_serialize::Encodable<S> for DepKind {
-            #[inline]
-            fn encode(&self, s: &mut S) {
-                s.emit_u16(*self as u16);
-            }
+            $(
+                // The `as u16` cast must be kept in sync with the inner type of `DepKind`.
+                pub const $variant: DepKind = DepKind::new(DepKindDefs::$variant as u16);
+            )*
         }
 
-        impl<D: rustc_serialize::Decoder> rustc_serialize::Decodable<D> for DepKind {
-            #[inline]
-            fn decode(d: &mut D) -> DepKind {
-                let discrim = d.read_u16();
-                assert!(discrim < DepKind::VARIANTS);
-                // SAFETY: DepKind::VARIANTS checks that the discriminant values permit
-                // this one check to soundly guard the transmute.
-                unsafe {
-                    std::mem::transmute::<u16, DepKind>(discrim)
+        // This checks that the discriminants of the variants have been assigned consecutively
+        // from 0 so that they can be used as a dense index.
+        pub const DEP_KIND_VARIANTS: u16 = {
+            let deps = &[$(dep_kinds::$variant,)*];
+            let mut i = 0;
+            while i < deps.len() {
+                if i != deps[i].as_usize() {
+                    panic!();
                 }
+                i += 1;
             }
-        }
+            deps.len() as u16
+        };
 
         pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
             match label {
-                $(stringify!($variant) => Ok(DepKind::$variant),)*
+                $(stringify!($variant) => Ok(dep_kinds::$variant),)*
                 _ => Err(()),
             }
         }
@@ -158,12 +142,10 @@ rustc_query_append!(define_dep_nodes![
     [] fn CompileMonoItem() -> (),
 ]);
 
-static_assert_size!(DepKind, 2);
-
 // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
 // Be very careful changing this type signature!
 pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
-    DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name)
+    DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name)
 }
 
 // WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys.
@@ -172,20 +154,9 @@ pub(crate) fn make_compile_mono_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     mono_item: &MonoItem<'tcx>,
 ) -> DepNode {
-    DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item)
+    DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item)
 }
 
-pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
-
-// We keep a lot of `DepNode`s in memory during compilation. It's not
-// required that their size stay the same, but we don't want to change
-// it inadvertently. This assert just ensures we're aware of any change.
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-static_assert_size!(DepNode, 18);
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-static_assert_size!(DepNode, 24);
-
 pub trait DepNodeExt: Sized {
     /// Extracts the DefId corresponding to this DepNode. This will work
     /// if two conditions are met:
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 87436f9eeed..76ef62f9f27 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -6,49 +6,24 @@ use rustc_session::Session;
 #[macro_use]
 mod dep_node;
 
+pub use rustc_query_system::dep_graph::debug::EdgeFilter;
 pub use rustc_query_system::dep_graph::{
-    debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex,
-    SerializedDepNodeIndex, WorkProduct, WorkProductId, WorkProductMap,
+    debug::DepNodeFilter, hash_result, DepContext, DepGraphQuery, DepNodeColor, DepNodeIndex, Deps,
+    SerializedDepGraph, SerializedDepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, WorkProductId,
+    WorkProductMap,
 };
 
-pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
+pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt};
 pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
 
-pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
+pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepsType>;
 
-pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
-pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
-pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
-pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
-pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
 pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>;
 
-impl rustc_query_system::dep_graph::DepKind for DepKind {
-    const NULL: Self = DepKind::Null;
-    const RED: Self = DepKind::Red;
-    const MAX: u16 = DepKind::VARIANTS - 1;
-
-    fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{:?}(", node.kind)?;
-
-        ty::tls::with_opt(|opt_tcx| {
-            if let Some(tcx) = opt_tcx {
-                if let Some(def_id) = node.extract_def_id(tcx) {
-                    write!(f, "{}", tcx.def_path_debug_str(def_id))?;
-                } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) {
-                    write!(f, "{s}")?;
-                } else {
-                    write!(f, "{}", node.hash)?;
-                }
-            } else {
-                write!(f, "{}", node.hash)?;
-            }
-            Ok(())
-        })?;
-
-        write!(f, ")")
-    }
+#[derive(Clone)]
+pub struct DepsType;
 
+impl Deps for DepsType {
     fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
     where
         OP: FnOnce() -> R,
@@ -70,24 +45,13 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
         })
     }
 
-    #[track_caller]
-    #[inline]
-    fn from_u16(u: u16) -> Self {
-        if u > Self::MAX {
-            panic!("Invalid DepKind {u}");
-        }
-        // SAFETY: See comment on DepKind::VARIANTS
-        unsafe { std::mem::transmute(u) }
-    }
-
-    #[inline]
-    fn to_u16(self) -> u16 {
-        self as u16
-    }
+    const DEP_KIND_NULL: DepKind = dep_kinds::Null;
+    const DEP_KIND_RED: DepKind = dep_kinds::Red;
+    const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1;
 }
 
 impl<'tcx> DepContext for TyCtxt<'tcx> {
-    type DepKind = DepKind;
+    type Deps = DepsType;
 
     #[inline]
     fn with_stable_hashing_context<R>(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R {
@@ -111,6 +75,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
 
     #[inline]
     fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> {
-        &self.query_kinds[dk as usize]
+        &self.query_kinds[dk.as_usize()]
     }
 }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index f67f8015c04..3491c487f3e 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -442,9 +442,10 @@ impl<'hir> Map<'hir> {
     /// Panics if `LocalDefId` does not have an associated body.
     pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
         match self.tcx.def_kind(def_id) {
-            DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => {
-                BodyOwnerKind::Const
+            DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
+                BodyOwnerKind::Const { inline: false }
             }
+            DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
             DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
             DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
             DefKind::Static(mt) => BodyOwnerKind::Static(mt),
@@ -461,7 +462,7 @@ impl<'hir> Map<'hir> {
     /// just that it has to be checked as if it were.
     pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
         let ccx = match self.body_owner_kind(def_id) {
-            BodyOwnerKind::Const => ConstContext::Const,
+            BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
             BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
 
             BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 037f84f476f..59849e8eb40 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -314,7 +314,10 @@ pub fn struct_lint_level(
             // Default allow lints trigger too often for testing.
             sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow,
             |incompat| {
-                matches!(incompat.reason, FutureIncompatibilityReason::FutureReleaseErrorReportNow)
+                matches!(
+                    incompat.reason,
+                    FutureIncompatibilityReason::FutureReleaseErrorReportInDeps
+                )
             },
         );
 
@@ -404,8 +407,8 @@ pub fn struct_lint_level(
 
         if let Some(future_incompatible) = future_incompatible {
             let explanation = match future_incompatible.reason {
-                FutureIncompatibilityReason::FutureReleaseError
-                | FutureIncompatibilityReason::FutureReleaseErrorReportNow => {
+                FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
+                | FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => {
                     "this was previously accepted by the compiler but is being phased out; \
                          it will become a hard error in a future release!"
                         .to_owned()
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 0115b1dcb3e..7c8a57b840b 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -6,13 +6,11 @@ use rustc_hir::{self as hir};
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, Size};
 
-use crate::mir::interpret::{
-    alloc_range, AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar,
-};
+use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar};
 use crate::mir::{pretty_print_const_value, Promoted};
+use crate::ty::ScalarInt;
 use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt};
 use crate::ty::{GenericArgs, GenericArgsRef};
-use crate::ty::{ScalarInt, UserTypeAnnotationIndex};
 
 ///////////////////////////////////////////////////////////////////////////
 /// Evaluated Constants
@@ -178,29 +176,10 @@ impl<'tcx> ConstValue<'tcx> {
 
 ///////////////////////////////////////////////////////////////////////////
 /// Constants
-///
-/// Two constants are equal if they are the same constant. Note that
-/// this does not necessarily mean that they are `==` in Rust. In
-/// particular, one must be wary of `NaN`!
-
-#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct Constant<'tcx> {
-    pub span: Span,
-
-    /// Optional user-given type: for something like
-    /// `collect::<Vec<_>>`, this would be present and would
-    /// indicate that `Vec<_>` was explicitly specified.
-    ///
-    /// Needed for NLL to impose user-given type constraints.
-    pub user_ty: Option<UserTypeAnnotationIndex>,
-
-    pub literal: ConstantKind<'tcx>,
-}
 
 #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
 #[derive(TypeFoldable, TypeVisitable)]
-pub enum ConstantKind<'tcx> {
+pub enum Const<'tcx> {
     /// This constant came from the type system.
     ///
     /// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
@@ -221,46 +200,27 @@ pub enum ConstantKind<'tcx> {
     Val(ConstValue<'tcx>, Ty<'tcx>),
 }
 
-impl<'tcx> Constant<'tcx> {
-    pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
-        match self.literal.try_to_scalar() {
-            Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
-                GlobalAlloc::Static(def_id) => {
-                    assert!(!tcx.is_thread_local_static(def_id));
-                    Some(def_id)
-                }
-                _ => None,
-            },
-            _ => None,
-        }
-    }
-    #[inline]
-    pub fn ty(&self) -> Ty<'tcx> {
-        self.literal.ty()
-    }
-}
-
-impl<'tcx> ConstantKind<'tcx> {
+impl<'tcx> Const<'tcx> {
     #[inline(always)]
     pub fn ty(&self) -> Ty<'tcx> {
         match self {
-            ConstantKind::Ty(c) => c.ty(),
-            ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => *ty,
+            Const::Ty(c) => c.ty(),
+            Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
         }
     }
 
     #[inline]
     pub fn try_to_scalar(self) -> Option<Scalar> {
         match self {
-            ConstantKind::Ty(c) => match c.kind() {
+            Const::Ty(c) => match c.kind() {
                 ty::ConstKind::Value(valtree) => match valtree {
                     ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
                     ty::ValTree::Branch(_) => None,
                 },
                 _ => None,
             },
-            ConstantKind::Val(val, _) => val.try_to_scalar(),
-            ConstantKind::Unevaluated(..) => None,
+            Const::Val(val, _) => val.try_to_scalar(),
+            Const::Unevaluated(..) => None,
         }
     }
 
@@ -287,17 +247,17 @@ impl<'tcx> ConstantKind<'tcx> {
         span: Option<Span>,
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
         match self {
-            ConstantKind::Ty(c) => {
+            Const::Ty(c) => {
                 // We want to consistently have a "clean" value for type system constants (i.e., no
                 // data hidden in the padding), so we always go through a valtree here.
                 let val = c.eval(tcx, param_env, span)?;
                 Ok(tcx.valtree_to_const_val((self.ty(), val)))
             }
-            ConstantKind::Unevaluated(uneval, _) => {
+            Const::Unevaluated(uneval, _) => {
                 // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
                 tcx.const_eval_resolve(param_env, uneval, span)
             }
-            ConstantKind::Val(val, _) => Ok(val),
+            Const::Val(val, _) => Ok(val),
         }
     }
 
@@ -332,23 +292,18 @@ impl<'tcx> ConstantKind<'tcx> {
     }
 
     #[inline]
-    pub fn try_eval_bits(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Option<u128> {
+    pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u128> {
         let int = self.try_eval_scalar_int(tcx, param_env)?;
-        assert_eq!(self.ty(), ty);
-        let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
+        let size =
+            tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
         int.to_bits(size).ok()
     }
 
     /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
     #[inline]
-    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
-        self.try_eval_bits(tcx, param_env, ty)
-            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
+    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
+        self.try_eval_bits(tcx, param_env)
+            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
     }
 
     #[inline]
@@ -416,7 +371,7 @@ impl<'tcx> ConstantKind<'tcx> {
         Self::Val(val, ty)
     }
 
-    /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
+    /// Literals are converted to `Const::Val`, const generic parameters are eagerly
     /// converted to a constant, everything else becomes `Unevaluated`.
     #[instrument(skip(tcx), level = "debug", ret)]
     pub fn from_anon_const(
@@ -552,29 +507,13 @@ impl<'tcx> UnevaluatedConst<'tcx> {
     }
 }
 
-impl<'tcx> Debug for Constant<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        write!(fmt, "{self}")
-    }
-}
-
-impl<'tcx> Display for Constant<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        match self.ty().kind() {
-            ty::FnDef(..) => {}
-            _ => write!(fmt, "const ")?,
-        }
-        Display::fmt(&self.literal, fmt)
-    }
-}
-
-impl<'tcx> Display for ConstantKind<'tcx> {
+impl<'tcx> Display for Const<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         match *self {
-            ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
-            ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
+            Const::Ty(c) => pretty_print_const(c, fmt, true),
+            Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
             // FIXME(valtrees): Correctly print mir constants.
-            ConstantKind::Unevaluated(..) => {
+            Const::Unevaluated(..) => {
                 fmt.write_str("_")?;
                 Ok(())
             }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 1efb54bdb08..9ef67392291 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -45,16 +45,6 @@ impl ExpressionId {
     }
 }
 
-rustc_index::newtype_index! {
-    /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
-    /// array position in the LLVM coverage map "Expressions" array, which is assembled during the
-    /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
-    #[derive(HashStable)]
-    #[max = 0xFFFF_FFFF]
-    #[debug_format = "MappedExpressionIndex({})"]
-    pub struct MappedExpressionIndex {}
-}
-
 /// Operand of a coverage-counter expression.
 ///
 /// Operands can be a constant zero value, an actual coverage counter, or another
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 87180b56baa..0bb1c66da0c 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -318,7 +318,7 @@ pub struct Body<'tcx> {
 
     /// Constants that are required to evaluate successfully for this MIR to be well-formed.
     /// We hold in this field all the constants we are not able to evaluate yet.
-    pub required_consts: Vec<Constant<'tcx>>,
+    pub required_consts: Vec<ConstOperand<'tcx>>,
 
     /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
     ///
@@ -585,12 +585,12 @@ impl<'tcx> Body<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
+        normalize_const: impl Fn(Const<'tcx>) -> Result<Const<'tcx>, ErrorHandled>,
     ) -> Result<(), ErrorHandled> {
         // For now, the only thing we have to check is is to ensure that all the constants used in
         // the body successfully evaluate.
         for &const_ in &self.required_consts {
-            let c = normalize_const(const_.literal)?;
+            let c = normalize_const(const_.const_)?;
             c.eval(tcx, param_env, Some(const_.span))?;
         }
 
@@ -1096,7 +1096,7 @@ impl<'tcx> LocalDecl<'tcx> {
 pub enum VarDebugInfoContents<'tcx> {
     /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
     Place(Place<'tcx>),
-    Const(Constant<'tcx>),
+    Const(ConstOperand<'tcx>),
 }
 
 impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index da3ab1b2a57..b43176a02d8 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -696,6 +696,17 @@ impl Debug for Statement<'_> {
     }
 }
 
+impl Display for NonDivergingIntrinsic<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Assume(op) => write!(f, "assume({op:?})"),
+            Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+                write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
+            }
+        }
+    }
+}
+
 impl<'tcx> Debug for TerminatorKind<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         self.fmt_head(fmt)?;
@@ -1058,6 +1069,22 @@ impl<'tcx> Debug for Operand<'tcx> {
     }
 }
 
+impl<'tcx> Debug for ConstOperand<'tcx> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        write!(fmt, "{self}")
+    }
+}
+
+impl<'tcx> Display for ConstOperand<'tcx> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        match self.ty().kind() {
+            ty::FnDef(..) => {}
+            _ => write!(fmt, "const ")?,
+        }
+        Display::fmt(&self.const_, fmt)
+    }
+}
+
 impl Debug for Place<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         self.as_ref().fmt(fmt)
@@ -1184,10 +1211,10 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool {
 }
 
 impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
-    fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
-        let Constant { span, user_ty, literal } = constant;
-        if use_verbose(literal.ty(), true) {
-            self.push("mir::Constant");
+    fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) {
+        let ConstOperand { span, user_ty, const_ } = constant;
+        if use_verbose(const_.ty(), true) {
+            self.push("mir::ConstOperand");
             self.push(&format!(
                 "+ span: {}",
                 self.tcx.sess.source_map().span_to_embeddable_string(*span)
@@ -1209,8 +1236,8 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                 ty::ValTree::Branch(_) => "Branch(..)".to_string(),
             };
 
-            let val = match literal {
-                ConstantKind::Ty(ct) => match ct.kind() {
+            let val = match const_ {
+                Const::Ty(ct) => match ct.kind() {
                     ty::ConstKind::Param(p) => format!("ty::Param({p})"),
                     ty::ConstKind::Unevaluated(uv) => {
                         format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
@@ -1222,9 +1249,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                     ty::ConstKind::Placeholder(_)
                     | ty::ConstKind::Infer(_)
                     | ty::ConstKind::Expr(_)
-                    | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal),
+                    | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", const_),
                 },
-                ConstantKind::Unevaluated(uv, _) => {
+                Const::Unevaluated(uv, _) => {
                     format!(
                         "Unevaluated({}, {:?}, {:?})",
                         self.tcx.def_path_str(uv.def),
@@ -1232,13 +1259,13 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                         uv.promoted,
                     )
                 }
-                ConstantKind::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)),
+                Const::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)),
             };
 
             // This reflects what `Const` looked liked before `val` was renamed
             // as `kind`. We print it like this to avoid having to update
             // expected output in a lot of tests.
-            self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val));
+            self.push(&format!("+ const_: Const {{ ty: {}, val: {} }}", const_.ty(), val));
         }
     }
 
@@ -1312,10 +1339,10 @@ pub fn write_allocations<'tcx>(
     struct CollectAllocIds(BTreeSet<AllocId>);
 
     impl<'tcx> Visitor<'tcx> for CollectAllocIds {
-        fn visit_constant(&mut self, c: &Constant<'tcx>, _: Location) {
-            match c.literal {
-                ConstantKind::Ty(_) | ConstantKind::Unevaluated(..) => {}
-                ConstantKind::Val(val, _) => {
+        fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) {
+            match c.const_ {
+                Const::Ty(_) | Const::Unevaluated(..) => {}
+                Const::Val(val, _) => {
                     self.0.extend(alloc_ids_from_const_val(val));
                 }
             }
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 25534f46960..5ac108bc829 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -1,5 +1,5 @@
 /// Functionality for statements, operands, places, and things that appear in them.
-use super::*;
+use super::{interpret::GlobalAlloc, *};
 
 ///////////////////////////////////////////////////////////////////////////
 // Statements
@@ -302,10 +302,10 @@ impl<'tcx> Operand<'tcx> {
         span: Span,
     ) -> Self {
         let ty = Ty::new_fn_def(tcx, def_id, args);
-        Operand::Constant(Box::new(Constant {
+        Operand::Constant(Box::new(ConstOperand {
             span,
             user_ty: None,
-            literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
+            const_: Const::Val(ConstValue::ZeroSized, ty),
         }))
     }
 
@@ -333,10 +333,10 @@ impl<'tcx> Operand<'tcx> {
             };
             scalar_size == type_size
         });
-        Operand::Constant(Box::new(Constant {
+        Operand::Constant(Box::new(ConstOperand {
             span,
             user_ty: None,
-            literal: ConstantKind::Val(ConstValue::Scalar(val), ty),
+            const_: Const::Val(ConstValue::Scalar(val), ty),
         }))
     }
 
@@ -356,9 +356,9 @@ impl<'tcx> Operand<'tcx> {
         }
     }
 
-    /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a
+    /// Returns the `ConstOperand` that is the target of this `Operand`, or `None` if this `Operand` is a
     /// place.
-    pub fn constant(&self) -> Option<&Constant<'tcx>> {
+    pub fn constant(&self) -> Option<&ConstOperand<'tcx>> {
         match self {
             Operand::Constant(x) => Some(&**x),
             Operand::Copy(_) | Operand::Move(_) => None,
@@ -370,11 +370,31 @@ impl<'tcx> Operand<'tcx> {
     /// While this is unlikely in general, it's the normal case of what you'll
     /// find as the `func` in a [`TerminatorKind::Call`].
     pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
-        let const_ty = self.constant()?.literal.ty();
+        let const_ty = self.constant()?.const_.ty();
         if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
     }
 }
 
+impl<'tcx> ConstOperand<'tcx> {
+    pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+        match self.const_.try_to_scalar() {
+            Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
+                GlobalAlloc::Static(def_id) => {
+                    assert!(!tcx.is_thread_local_static(def_id));
+                    Some(def_id)
+                }
+                _ => None,
+            },
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn ty(&self) -> Ty<'tcx> {
+        self.const_.ty()
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 /// Rvalues
 
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index f99084d0eb7..8f651b2a2db 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -3,7 +3,7 @@
 //! This is in a dedicated file so that changes to this file can be reviewed more carefully.
 //! The intention is that this file only contains datatype declarations, no code.
 
-use super::{BasicBlock, Constant, Local, UserTypeProjection};
+use super::{BasicBlock, Const, Local, UserTypeProjection};
 
 use crate::mir::coverage::{CodeRegion, CoverageKind};
 use crate::traits::Reveal;
@@ -439,17 +439,6 @@ pub enum NonDivergingIntrinsic<'tcx> {
     CopyNonOverlapping(CopyNonOverlapping<'tcx>),
 }
 
-impl std::fmt::Display for NonDivergingIntrinsic<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Assume(op) => write!(f, "assume({op:?})"),
-            Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
-                write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
-            }
-        }
-    }
-}
-
 /// Describes what kind of retag is to be performed.
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
 #[rustc_pass_by_value]
@@ -913,10 +902,10 @@ pub enum InlineAsmOperand<'tcx> {
         out_place: Option<Place<'tcx>>,
     },
     Const {
-        value: Box<Constant<'tcx>>,
+        value: Box<ConstOperand<'tcx>>,
     },
     SymFn {
-        value: Box<Constant<'tcx>>,
+        value: Box<ConstOperand<'tcx>>,
     },
     SymStatic {
         def_id: DefId,
@@ -1136,7 +1125,22 @@ pub enum Operand<'tcx> {
     Move(Place<'tcx>),
 
     /// Constants are already semantically values, and remain unchanged.
-    Constant(Box<Constant<'tcx>>),
+    Constant(Box<ConstOperand<'tcx>>),
+}
+
+#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ConstOperand<'tcx> {
+    pub span: Span,
+
+    /// Optional user-given type: for something like
+    /// `collect::<Vec<_>>`, this would be present and would
+    /// indicate that `Vec<_>` was explicitly specified.
+    ///
+    /// Needed for NLL to impose user-given type constraints.
+    pub user_ty: Option<UserTypeAnnotationIndex>,
+
+    pub const_: Const<'tcx>,
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index f79697936d2..01c04f63890 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -227,7 +227,7 @@ impl<'tcx> Operand<'tcx> {
     {
         match self {
             &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
-            Operand::Constant(c) => c.literal.ty(),
+            Operand::Constant(c) => c.const_.ty(),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 61244b94289..51ec6da1ac8 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -186,7 +186,7 @@ macro_rules! make_mir_visitor {
 
             fn visit_constant(
                 &mut self,
-                constant: & $($mutability)? Constant<'tcx>,
+                constant: & $($mutability)? ConstOperand<'tcx>,
                 location: Location,
             ) {
                 self.super_constant(constant, location);
@@ -870,20 +870,20 @@ macro_rules! make_mir_visitor {
 
             fn super_constant(
                 &mut self,
-                constant: & $($mutability)? Constant<'tcx>,
+                constant: & $($mutability)? ConstOperand<'tcx>,
                 location: Location
             ) {
-                let Constant {
+                let ConstOperand {
                     span,
                     user_ty: _, // no visit method for this
-                    literal,
+                    const_,
                 } = constant;
 
                 self.visit_span($(& $mutability)? *span);
-                match literal {
-                    ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
-                    ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
-                    ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
+                match const_ {
+                    Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
+                    Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
+                    Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
                 }
             }
 
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 247fcd20c6c..8ba3764bcc3 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -116,9 +116,8 @@ impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> {
     type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()];
 }
 
-impl EraseType for Result<mir::ConstantKind<'_>, mir::interpret::LitToConstError> {
-    type Result =
-        [u8; size_of::<Result<mir::ConstantKind<'static>, mir::interpret::LitToConstError>>()];
+impl EraseType for Result<mir::Const<'_>, mir::interpret::LitToConstError> {
+    type Result = [u8; size_of::<Result<mir::Const<'static>, mir::interpret::LitToConstError>>()];
 }
 
 impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
@@ -266,6 +265,7 @@ trivial! {
     rustc_middle::ty::adjustment::CoerceUnsizedInfo,
     rustc_middle::ty::AssocItem,
     rustc_middle::ty::AssocItemContainer,
+    rustc_middle::ty::Asyncness,
     rustc_middle::ty::BoundVariableKind,
     rustc_middle::ty::DeducedParamAttrs,
     rustc_middle::ty::Destructor,
@@ -311,7 +311,7 @@ macro_rules! tcx_lifetime {
 tcx_lifetime! {
     rustc_middle::hir::Owner,
     rustc_middle::middle::exported_symbols::ExportedSymbol,
-    rustc_middle::mir::ConstantKind,
+    rustc_middle::mir::Const,
     rustc_middle::mir::DestructuredConstant,
     rustc_middle::mir::ConstAlloc,
     rustc_middle::mir::ConstValue,
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index af4c57e702f..b1f83796862 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -416,7 +416,7 @@ impl<'tcx> Key for GenericArg<'tcx> {
     }
 }
 
-impl<'tcx> Key for mir::ConstantKind<'tcx> {
+impl<'tcx> Key for mir::Const<'tcx> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b5529568ff2..d888a2c0fb6 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -7,7 +7,6 @@
 #![allow(unused_parens)]
 
 use crate::dep_graph;
-use crate::dep_graph::DepKind;
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintExpectation;
 use crate::metadata::ModChild;
@@ -731,7 +730,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query asyncness(key: DefId) -> hir::IsAsync {
+    query asyncness(key: DefId) -> ty::Asyncness {
         desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
         separate_provide_extern
     }
@@ -1101,7 +1100,7 @@ rustc_queries! {
         desc { "destructuring type level constant"}
     }
 
-    /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
+    /// Tries to destructure an `mir::Const` ADT or array into its variant index
     /// and its field values. This should only be used for pretty printing.
     query try_destructure_mir_constant_for_diagnostics(
         key: (mir::ConstValue<'tcx>, Ty<'tcx>)
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index a342b5231e9..34e5b02ba5b 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -37,7 +37,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
     pub eval_always: bool,
     pub dep_kind: DepKind,
     pub handle_cycle_error: HandleCycleError,
-    pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>,
+    pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key>>,
     pub query_cache: FieldOffset<QueryCaches<'tcx>, C>,
     pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
     pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
@@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
         fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
     pub hash_result: HashResult<C::Value>,
     pub value_from_cycle_error:
-        fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>], guar: ErrorGuaranteed) -> C::Value,
+        fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value,
     pub format_value: fn(&C::Value) -> String,
 }
 
@@ -402,7 +402,7 @@ macro_rules! define_callbacks {
         #[derive(Default)]
         pub struct QueryStates<'tcx> {
             $(
-                pub $name: QueryState<$($K)*, DepKind>,
+                pub $name: QueryState<$($K)*>,
             )*
         }
 
@@ -516,7 +516,7 @@ macro_rules! define_feedable {
                         }
                     }
                     None => {
-                        let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
+                        let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::dep_kinds::$name, &key);
                         let dep_node_index = tcx.dep_graph.with_feed_task(
                             dep_node,
                             tcx,
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index ebc1c11902b..8c39614903c 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -563,11 +563,11 @@ pub enum InlineAsmOperand<'tcx> {
         out_expr: Option<ExprId>,
     },
     Const {
-        value: mir::ConstantKind<'tcx>,
+        value: mir::Const<'tcx>,
         span: Span,
     },
     SymFn {
-        value: mir::ConstantKind<'tcx>,
+        value: mir::Const<'tcx>,
         span: Span,
     },
     SymStatic {
@@ -739,7 +739,7 @@ pub enum PatKind<'tcx> {
     /// * Opaque constants, that must not be matched structurally. So anything that does not derive
     ///   `PartialEq` and `Eq`.
     Constant {
-        value: mir::ConstantKind<'tcx>,
+        value: mir::Const<'tcx>,
     },
 
     Range(Box<PatRange<'tcx>>),
@@ -769,8 +769,8 @@ pub enum PatKind<'tcx> {
 
 #[derive(Clone, Debug, PartialEq, HashStable)]
 pub struct PatRange<'tcx> {
-    pub lo: mir::ConstantKind<'tcx>,
-    pub hi: mir::ConstantKind<'tcx>,
+    pub lo: mir::Const<'tcx>,
+    pub hi: mir::Const<'tcx>,
     pub end: RangeEnd,
 }
 
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 681400dbb94..b84e1568884 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -26,13 +26,13 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
         walk_pat(self, pat);
     }
 
-    // Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
+    // Note: We don't have visitors for `ty::Const` and `mir::Const`
     // (even though these types occur in THIR) for consistency and to reduce confusion,
     // since the lazy creation of constants during thir construction causes most
-    // 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
+    // 'constants' to not be of type `ty::Const` or `mir::Const` at that
     // stage (they are mostly still identified by `DefId` or `hir::Lit`, see
     // the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
-    // You have to manually visit `ty::Const` and `mir::ConstantKind` through the
+    // You have to manually visit `ty::Const` and `mir::Const` through the
     // other `visit*` functions.
 }
 
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 1340e674568..eef193a657d 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -378,6 +378,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// `start` has wrong type
     StartFunctionType,
 
+    /// language function has wrong type
+    LangFunctionType(Symbol),
+
     /// Intrinsic has wrong type
     IntrinsicType,
 
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index ba871d6478b..2518f0cf2e9 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -339,24 +339,19 @@ impl<'tcx> Const<'tcx> {
     /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
     /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
     /// contains const generic parameters or pointers).
-    pub fn try_eval_bits(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Option<u128> {
+    pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
         let int = self.try_eval_scalar_int(tcx, param_env)?;
-        assert_eq!(self.ty(), ty);
-        let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
+        let size =
+            tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
         // if `ty` does not depend on generic parameters, use an empty param_env
         int.to_bits(size).ok()
     }
 
     #[inline]
     /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
-    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
-        self.try_eval_bits(tcx, param_env, ty)
-            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
+    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 {
+        self.try_eval_bits(tcx, param_env)
+            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index dbff13fdd8e..b050208b4a6 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -280,6 +280,19 @@ impl fmt::Display for ImplPolarity {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum Asyncness {
+    Yes,
+    No,
+}
+
+impl Asyncness {
+    pub fn is_async(self) -> bool {
+        matches!(self, Asyncness::Yes)
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
 pub enum Visibility<Id = LocalDefId> {
     /// Visible everywhere (including in other crates).
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index f1c38984296..f1093e88312 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -62,6 +62,7 @@ trivially_parameterized_over_tcx! {
     crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
     crate::mir::ConstQualifs,
     ty::AssocItemContainer,
+    ty::Asyncness,
     ty::DeducedParamAttrs,
     ty::Generics,
     ty::ImplPolarity,
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 268339ed402..b66c0f20990 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -479,7 +479,6 @@ TrivialTypeTraversalImpls! {
     ::rustc_target::asm::InlineAsmRegOrRegClass,
     crate::mir::coverage::CounterId,
     crate::mir::coverage::ExpressionId,
-    crate::mir::coverage::MappedExpressionIndex,
     crate::mir::Local,
     crate::mir::Promoted,
     crate::traits::Reveal,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 3ebb8cbc476..f0526a23714 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2946,6 +2946,11 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
+    /// Returns `true` when the outermost type cannot be further normalized,
+    /// resolved, or substituted. This includes all primitive types, but also
+    /// things like ADTs and trait objects, sice even if their arguments or
+    /// nested types may be further simplified, the outermost [`TyKind`] or
+    /// type constructor remains the same.
     pub fn is_known_rigid(self) -> bool {
         match self.kind() {
             Bool
diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs
index 1b845334c49..9f1e4ac11c2 100644
--- a/compiler/rustc_middle/src/util/find_self_call.rs
+++ b/compiler/rustc_middle/src/util/find_self_call.rs
@@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>(
         &body[block].terminator
     {
         debug!("find_self_call: func={:?}", func);
-        if let Operand::Constant(box Constant { literal, .. }) = func {
-            if let ty::FnDef(def_id, fn_args) = *literal.ty().kind() {
+        if let Operand::Constant(box ConstOperand { const_, .. }) = func {
+            if let ty::FnDef(def_id, fn_args) = *const_.ty().kind() {
                 if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
                     tcx.opt_associated_item(def_id)
                 {
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 962faf56cb8..dec06363380 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -1,4 +1,4 @@
-use crate::dep_graph::DepKind;
+use crate::dep_graph::dep_kinds;
 use crate::query::plumbing::CyclePlaceholder;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
@@ -13,34 +13,22 @@ use rustc_span::{ErrorGuaranteed, Span};
 
 use std::fmt::Write;
 
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
-    fn from_cycle_error(
-        tcx: TyCtxt<'tcx>,
-        _: &[QueryInfo<DepKind>],
-        guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
         // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
-    fn from_cycle_error(
-        _tcx: TyCtxt<'tcx>,
-        _: &[QueryInfo<DepKind>],
-        guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
+    fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
         Err(CyclePlaceholder(guar))
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
-    fn from_cycle_error(
-        tcx: TyCtxt<'tcx>,
-        _: &[QueryInfo<DepKind>],
-        _guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
         // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe {
@@ -51,16 +39,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
-    fn from_cycle_error(
-        tcx: TyCtxt<'tcx>,
-        stack: &[QueryInfo<DepKind>],
-        guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
         let err = Ty::new_error(tcx, guar);
 
         let arity = if let Some(frame) = stack.get(0)
-            && frame.query.dep_kind == DepKind::fn_sig
+            && frame.query.dep_kind == dep_kinds::fn_sig
             && let Some(def_id) = frame.query.def_id
             && let Some(node) = tcx.hir().get_if_local(def_id)
             && let Some(sig) = node.fn_sig()
@@ -85,16 +69,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
-    fn from_cycle_error(
-        tcx: TyCtxt<'tcx>,
-        cycle: &[QueryInfo<DepKind>],
-        _guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
         let mut item_and_field_ids = Vec::new();
         let mut representable_ids = FxHashSet::default();
         for info in cycle {
-            if info.query.dep_kind == DepKind::representability
+            if info.query.dep_kind == dep_kinds::representability
                 && let Some(field_id) = info.query.def_id
                 && let Some(field_id) = field_id.as_local()
                 && let Some(DefKind::Field) = info.query.def_kind
@@ -108,7 +88,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
             }
         }
         for info in cycle {
-            if info.query.dep_kind == DepKind::representability_adt_ty
+            if info.query.dep_kind == dep_kinds::representability_adt_ty
                 && let Some(def_id) = info.query.ty_adt_id
                 && let Some(def_id) = def_id.as_local()
                 && !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
@@ -121,32 +101,20 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
-    fn from_cycle_error(
-        tcx: TyCtxt<'tcx>,
-        cycle: &[QueryInfo<DepKind>],
-        guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
         ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar))
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
-    fn from_cycle_error(
-        tcx: TyCtxt<'tcx>,
-        cycle: &[QueryInfo<DepKind>],
-        guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
         ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar))
     }
 }
 
-impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
-    fn from_cycle_error(
-        _tcx: TyCtxt<'tcx>,
-        _cycle: &[QueryInfo<DepKind>],
-        _guar: ErrorGuaranteed,
-    ) -> Self {
+impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
+    fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
         // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
         // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
         // tcx.arena.alloc is pretty much equal to leaking).
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index 4f1623b4c6a..fddcf9de7c7 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -49,7 +49,7 @@ impl<'tcx> CFG<'tcx> {
         block: BasicBlock,
         source_info: SourceInfo,
         temp: Place<'tcx>,
-        constant: Constant<'tcx>,
+        constant: ConstOperand<'tcx>,
     ) {
         self.push_assign(
             block,
@@ -70,10 +70,10 @@ impl<'tcx> CFG<'tcx> {
             block,
             source_info,
             place,
-            Rvalue::Use(Operand::Constant(Box::new(Constant {
+            Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
                 span: source_info.span,
                 user_ty: None,
-                literal: ConstantKind::zero_sized(tcx.types.unit),
+                const_: Const::zero_sized(tcx.types.unit),
             }))),
         );
     }
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 0eff2df1366..fd2c57a0a6f 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -100,7 +100,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
                     expected: "constant pattern".to_string(),
                 });
             };
-            values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
+            values.push(value.eval_bits(self.tcx, self.param_env));
             targets.push(self.parse_block(arm.body)?);
         }
 
@@ -283,12 +283,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             ExprKind::StaticRef { alloc_id, ty, .. } => {
                 let const_val =
                     ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
-                let literal = ConstantKind::Val(const_val, *ty);
+                let const_ = Const::Val(const_val, *ty);
 
-                Ok(Operand::Constant(Box::new(Constant {
+                Ok(Operand::Constant(Box::new(ConstOperand {
                     span: expr.span,
                     user_ty: None,
-                    literal
+                    const_
                 })))
             },
         )
@@ -301,7 +301,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             | ExprKind::NonHirLiteral { .. }
             | ExprKind::ConstBlock { .. } => Ok({
                 let value = as_constant_inner(expr, |_| None, self.tcx);
-                value.literal.eval_bits(self.tcx, self.param_env, value.ty())
+                value.const_.eval_bits(self.tcx, self.param_env)
             }),
         )
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index d8232199e01..4ed49e78738 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -15,7 +15,7 @@ use rustc_target::abi::Size;
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
     /// `expr` is a valid compile-time constant!
-    pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
+    pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> ConstOperand<'tcx> {
         let this = self;
         let tcx = this.tcx;
         let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
@@ -42,62 +42,62 @@ pub fn as_constant_inner<'tcx>(
     expr: &Expr<'tcx>,
     push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
     tcx: TyCtxt<'tcx>,
-) -> Constant<'tcx> {
+) -> ConstOperand<'tcx> {
     let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
     match *kind {
         ExprKind::Literal { lit, neg } => {
-            let literal =
-                match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
-                    Ok(c) => c,
-                    Err(LitToConstError::Reported(guar)) => {
-                        ConstantKind::Ty(ty::Const::new_error(tcx, guar, ty))
-                    }
-                    Err(LitToConstError::TypeError) => {
-                        bug!("encountered type error in `lit_to_mir_constant`")
-                    }
-                };
-
-            Constant { span, user_ty: None, literal }
+            let const_ = match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg })
+            {
+                Ok(c) => c,
+                Err(LitToConstError::Reported(guar)) => {
+                    Const::Ty(ty::Const::new_error(tcx, guar, ty))
+                }
+                Err(LitToConstError::TypeError) => {
+                    bug!("encountered type error in `lit_to_mir_constant`")
+                }
+            };
+
+            ConstOperand { span, user_ty: None, const_ }
         }
         ExprKind::NonHirLiteral { lit, ref user_ty } => {
             let user_ty = user_ty.as_ref().and_then(push_cuta);
 
-            let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
+            let const_ = Const::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
 
-            Constant { span, user_ty, literal }
+            ConstOperand { span, user_ty, const_ }
         }
         ExprKind::ZstLiteral { ref user_ty } => {
             let user_ty = user_ty.as_ref().and_then(push_cuta);
 
-            let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
+            let const_ = Const::Val(ConstValue::ZeroSized, ty);
 
-            Constant { span, user_ty, literal }
+            ConstOperand { span, user_ty, const_ }
         }
         ExprKind::NamedConst { def_id, args, ref user_ty } => {
             let user_ty = user_ty.as_ref().and_then(push_cuta);
 
             let uneval = mir::UnevaluatedConst::new(def_id, args);
-            let literal = ConstantKind::Unevaluated(uneval, ty);
+            let const_ = Const::Unevaluated(uneval, ty);
 
-            Constant { user_ty, span, literal }
+            ConstOperand { user_ty, span, const_ }
         }
         ExprKind::ConstParam { param, def_id: _ } => {
             let const_param = ty::Const::new_param(tcx, param, expr.ty);
-            let literal = ConstantKind::Ty(const_param);
+            let const_ = Const::Ty(const_param);
 
-            Constant { user_ty: None, span, literal }
+            ConstOperand { user_ty: None, span, const_ }
         }
         ExprKind::ConstBlock { did: def_id, args } => {
             let uneval = mir::UnevaluatedConst::new(def_id, args);
-            let literal = ConstantKind::Unevaluated(uneval, ty);
+            let const_ = Const::Unevaluated(uneval, ty);
 
-            Constant { user_ty: None, span, literal }
+            ConstOperand { user_ty: None, span, const_ }
         }
         ExprKind::StaticRef { alloc_id, ty, .. } => {
             let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
-            let literal = ConstantKind::Val(const_val, ty);
+            let const_ = Const::Val(const_val, ty);
 
-            Constant { span, user_ty: None, literal }
+            ConstOperand { span, user_ty: None, const_ }
         }
         _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
     }
@@ -107,7 +107,7 @@ pub fn as_constant_inner<'tcx>(
 fn lit_to_mir_constant<'tcx>(
     tcx: TyCtxt<'tcx>,
     lit_input: LitToConstInput<'tcx>,
-) -> Result<ConstantKind<'tcx>, LitToConstError> {
+) -> Result<Const<'tcx>, LitToConstError> {
     let LitToConstInput { lit, ty, neg } = lit_input;
     let trunc = |n| {
         let param_ty = ty::ParamEnv::reveal_all().and(ty);
@@ -173,5 +173,5 @@ fn lit_to_mir_constant<'tcx>(
         _ => return Err(LitToConstError::TypeError),
     };
 
-    Ok(ConstantKind::Val(value, ty))
+    Ok(Const::Val(value, ty))
 }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 3220a184d49..d4089eef483 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -249,7 +249,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                         let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
                             let range_val =
-                                ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
+                                Const::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
                             let lit_op = this.literal_operand(expr.span, range_val);
                             let is_bin_op = this.temp(bool_ty, expr_span);
                             this.cfg.push_assign(
@@ -485,10 +485,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
                 block = unpack!(this.stmt_expr(block, expr, None));
-                block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
+                block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
                     span: expr_span,
                     user_ty: None,
-                    literal: ConstantKind::zero_sized(this.tcx.types.unit),
+                    const_: Const::zero_sized(this.tcx.types.unit),
                 }))))
             }
 
@@ -817,7 +817,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let param_ty = ty::ParamEnv::empty().and(ty);
         let size = self.tcx.layout_of(param_ty).unwrap().size;
-        let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
+        let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
 
         self.literal_operand(span, literal)
     }
@@ -828,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let param_ty = ty::ParamEnv::empty().and(ty);
         let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
         let n = 1 << (bits - 1);
-        let literal = ConstantKind::from_bits(self.tcx, n, param_ty);
+        let literal = Const::from_bits(self.tcx, n, param_ty);
 
         self.literal_operand(span, literal)
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 1e0a47ead8c..a4de42d45c9 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -114,10 +114,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     true_block,
                     source_info,
                     destination,
-                    Constant {
+                    ConstOperand {
                         span: expr_span,
                         user_ty: None,
-                        literal: ConstantKind::from_bool(this.tcx, true),
+                        const_: Const::from_bool(this.tcx, true),
                     },
                 );
 
@@ -125,10 +125,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     false_block,
                     source_info,
                     destination,
-                    Constant {
+                    ConstOperand {
                         span: expr_span,
                         user_ty: None,
-                        literal: ConstantKind::from_bool(this.tcx, false),
+                        const_: Const::from_bool(this.tcx, false),
                     },
                 );
 
@@ -186,10 +186,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     short_circuit,
                     source_info,
                     destination,
-                    Constant {
+                    ConstOperand {
                         span: expr.span,
                         user_ty: None,
-                        literal: ConstantKind::from_bool(this.tcx, constant),
+                        const_: Const::from_bool(this.tcx, constant),
                     },
                 );
                 let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs]));
@@ -433,12 +433,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         }
                         thir::InlineAsmOperand::Const { value, span } => {
                             mir::InlineAsmOperand::Const {
-                                value: Box::new(Constant { span, user_ty: None, literal: value }),
+                                value: Box::new(ConstOperand {
+                                    span,
+                                    user_ty: None,
+                                    const_: value,
+                                }),
                             }
                         }
                         thir::InlineAsmOperand::SymFn { value, span } => {
                             mir::InlineAsmOperand::SymFn {
-                                value: Box::new(Constant { span, user_ty: None, literal: value }),
+                                value: Box::new(ConstOperand {
+                                    span,
+                                    user_ty: None,
+                                    const_: value,
+                                }),
                             }
                         }
                         thir::InlineAsmOperand::SymStatic { def_id } => {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 7e81c8b50c2..921a5ca1175 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1005,13 +1005,13 @@ enum TestKind<'tcx> {
         ///
         /// For `bool` we always generate two edges, one for `true` and one for
         /// `false`.
-        options: FxIndexMap<ConstantKind<'tcx>, u128>,
+        options: FxIndexMap<Const<'tcx>, u128>,
     },
 
     /// Test for equality with value, possibly after an unsizing coercion to
     /// `ty`,
     Eq {
-        value: ConstantKind<'tcx>,
+        value: Const<'tcx>,
         // Integer types are handled by `SwitchInt`, and constants with ADT
         // types are converted back into patterns, so this can only be `&str`,
         // `&[T]`, `f32` or `f64`.
@@ -1622,9 +1622,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // may want to add cases based on the candidates that are
         // available
         match test.kind {
-            TestKind::SwitchInt { switch_ty, ref mut options } => {
+            TestKind::SwitchInt { switch_ty: _, ref mut options } => {
                 for candidate in candidates.iter() {
-                    if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) {
+                    if !self.add_cases_to_switch(&match_place, candidate, options) {
                         break;
                     }
                 }
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 484e8490919..795d1db8eec 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -85,8 +85,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         test_place: &PlaceBuilder<'tcx>,
         candidate: &Candidate<'pat, 'tcx>,
-        switch_ty: Ty<'tcx>,
-        options: &mut FxIndexMap<ConstantKind<'tcx>, u128>,
+        options: &mut FxIndexMap<Const<'tcx>, u128>,
     ) -> bool {
         let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place)
         else {
@@ -95,9 +94,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         match match_pair.pattern.kind {
             PatKind::Constant { value } => {
-                options
-                    .entry(value)
-                    .or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty));
+                options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env));
                 true
             }
             PatKind::Variant { .. } => {
@@ -255,10 +252,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         block,
                         source_info,
                         TerminatorKind::Call {
-                            func: Operand::Constant(Box::new(Constant {
+                            func: Operand::Constant(Box::new(ConstOperand {
                                 span: test.span,
                                 user_ty: None,
-                                literal: method,
+                                const_: method,
                             })),
                             args: vec![Operand::Move(ref_string)],
                             destination: ref_str,
@@ -388,7 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block: BasicBlock,
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
         source_info: SourceInfo,
-        value: ConstantKind<'tcx>,
+        value: Const<'tcx>,
         mut val: Place<'tcx>,
         mut ty: Ty<'tcx>,
     ) {
@@ -485,7 +482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             block,
             source_info,
             TerminatorKind::Call {
-                func: Operand::Constant(Box::new(Constant {
+                func: Operand::Constant(Box::new(ConstOperand {
                     span: source_info.span,
 
                     // FIXME(#54571): This constant comes from user input (a
@@ -494,7 +491,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // Need to experiment.
                     user_ty: None,
 
-                    literal: method,
+                    const_: method,
                 })),
                 args: vec![Operand::Copy(val), expect],
                 destination: eq_result,
@@ -800,11 +797,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
     }
 
-    fn const_range_contains(
-        &self,
-        range: &PatRange<'tcx>,
-        value: ConstantKind<'tcx>,
-    ) -> Option<bool> {
+    fn const_range_contains(&self, range: &PatRange<'tcx>, value: Const<'tcx>) -> Option<bool> {
         use std::cmp::Ordering::*;
 
         // For performance, it's important to only do the second
@@ -821,7 +814,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn values_not_contained_in_range(
         &self,
         range: &PatRange<'tcx>,
-        options: &FxIndexMap<ConstantKind<'tcx>, u128>,
+        options: &FxIndexMap<Const<'tcx>, u128>,
     ) -> Option<bool> {
         for &val in options.keys() {
             if self.const_range_contains(range, val)? {
@@ -866,7 +859,7 @@ fn trait_method<'tcx>(
     trait_def_id: DefId,
     method_name: Symbol,
     args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-) -> ConstantKind<'tcx> {
+) -> Const<'tcx> {
     // The unhygienic comparison here is acceptable because this is only
     // used on known traits.
     let item = tcx
@@ -877,5 +870,5 @@ fn trait_method<'tcx>(
 
     let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
 
-    ConstantKind::zero_sized(method_ty)
+    Const::zero_sized(method_ty)
 }
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index 90d78658f96..c96e99ef0e7 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -25,19 +25,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     /// Convenience function for creating a literal operand, one
     /// without any user type annotation.
-    pub(crate) fn literal_operand(
-        &mut self,
-        span: Span,
-        literal: ConstantKind<'tcx>,
-    ) -> Operand<'tcx> {
-        let constant = Box::new(Constant { span, user_ty: None, literal });
+    pub(crate) fn literal_operand(&mut self, span: Span, const_: Const<'tcx>) -> Operand<'tcx> {
+        let constant = Box::new(ConstOperand { span, user_ty: None, const_ });
         Operand::Constant(constant)
     }
 
     /// Returns a zero literal operand for the appropriate type, works for
     /// bool, char and integers.
     pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
+        let literal = Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
 
         self.literal_operand(span, literal)
     }
@@ -54,10 +50,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             block,
             source_info,
             temp,
-            Constant {
+            ConstOperand {
                 span: source_info.span,
                 user_ty: None,
-                literal: ConstantKind::from_usize(self.tcx, value),
+                const_: Const::from_usize(self.tcx, value),
             },
         );
         temp
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 7748ffab79c..bba47056457 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -633,7 +633,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo
                 _ => bug!("expected closure or generator, found {ty:?}"),
             }
         }
-        hir::BodyOwnerKind::Const => 0,
+        hir::BodyOwnerKind::Const { .. } => 0,
         hir::BodyOwnerKind::Static(_) => 0,
     };
     let mut cfg = CFG { basic_blocks: IndexVec::new() };
@@ -700,7 +700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // Constants always need overflow checks.
         check_overflow |= matches!(
             tcx.hir().body_owner_kind(def),
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
+            hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_)
         );
 
         let lint_level = LintLevel::Explicit(hir_id);
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 18b0e9a643e..16a85d42761 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -647,21 +647,15 @@ impl<'tcx> Cx<'tcx> {
                             out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
                         },
                         hir::InlineAsmOperand::Const { ref anon_const } => {
-                            let value = mir::ConstantKind::from_anon_const(
-                                tcx,
-                                anon_const.def_id,
-                                self.param_env,
-                            );
+                            let value =
+                                mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
                             let span = tcx.def_span(anon_const.def_id);
 
                             InlineAsmOperand::Const { value, span }
                         }
                         hir::InlineAsmOperand::SymFn { ref anon_const } => {
-                            let value = mir::ConstantKind::from_anon_const(
-                                tcx,
-                                anon_const.def_id,
-                                self.param_env,
-                            );
+                            let value =
+                                mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
                             let span = tcx.def_span(anon_const.def_id);
 
                             InlineAsmOperand::SymFn { value, span }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 1376344cfda..00d9fe72cfc 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -27,7 +27,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     #[instrument(level = "debug", skip(self), ret)]
     pub(super) fn const_to_pat(
         &self,
-        cv: mir::ConstantKind<'tcx>,
+        cv: mir::Const<'tcx>,
         id: hir::HirId,
         span: Span,
         check_body_for_struct_match_violation: Option<DefId>,
@@ -104,7 +104,7 @@ impl<'tcx> ConstToPat<'tcx> {
 
     fn to_pat(
         &mut self,
-        cv: mir::ConstantKind<'tcx>,
+        cv: mir::Const<'tcx>,
         check_body_for_struct_match_violation: Option<DefId>,
     ) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
@@ -124,7 +124,7 @@ impl<'tcx> ConstToPat<'tcx> {
         debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
 
         let inlined_const_as_pat = match cv {
-            mir::ConstantKind::Ty(c) => match c.kind() {
+            mir::Const::Ty(c) => match c.kind() {
                 ty::ConstKind::Param(_)
                 | ty::ConstKind::Infer(_)
                 | ty::ConstKind::Bound(_, _)
@@ -144,10 +144,10 @@ impl<'tcx> ConstToPat<'tcx> {
                         })
                     }),
             },
-            mir::ConstantKind::Unevaluated(_, _) => {
+            mir::Const::Unevaluated(_, _) => {
                 span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
             }
-            mir::ConstantKind::Val(_, _) => Box::new(Pat {
+            mir::Const::Val(_, _) => Box::new(Pat {
                 span: self.span,
                 ty: cv.ty(),
                 kind: PatKind::Constant { value: cv },
@@ -385,9 +385,9 @@ impl<'tcx> ConstToPat<'tcx> {
             ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
                 // `&str` is represented as a valtree, let's keep using this
                 // optimization for now.
-                ty::Str => PatKind::Constant {
-                    value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
-                },
+                ty::Str => {
+                    PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
+                }
                 // Backwards compatibility hack: support references to non-structural types,
                 // but hard error if we aren't behind a double reference. We could just use
                 // the fallback code path below, but that would allow *more* of this fishy
@@ -445,9 +445,9 @@ impl<'tcx> ConstToPat<'tcx> {
                     }
                 }
             },
-            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => PatKind::Constant {
-                value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
-            },
+            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
+                PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
+            }
             ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
             _ => {
                 self.saw_const_match_error.set(true);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index bee1c4e4614..b79beb1c537 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -137,16 +137,16 @@ impl IntRange {
     fn from_constant<'tcx>(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: mir::ConstantKind<'tcx>,
+        value: mir::Const<'tcx>,
     ) -> Option<IntRange> {
         let ty = value.ty();
         let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?;
         let val = match value {
-            mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
+            mir::Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
                 valtree.unwrap_leaf().to_bits(target_size).ok()
             },
             // This is a more general form of the previous case.
-            _ => value.try_eval_bits(tcx, param_env, ty),
+            _ => value.try_eval_bits(tcx, param_env),
         }?;
 
         let val = val ^ bias;
@@ -225,8 +225,8 @@ impl IntRange {
         let (lo, hi) = (lo ^ bias, hi ^ bias);
 
         let env = ty::ParamEnv::empty().and(ty);
-        let lo_const = mir::ConstantKind::from_bits(tcx, lo, env);
-        let hi_const = mir::ConstantKind::from_bits(tcx, hi, env);
+        let lo_const = mir::Const::from_bits(tcx, lo, env);
+        let hi_const = mir::Const::from_bits(tcx, hi, env);
 
         let kind = if lo == hi {
             PatKind::Constant { value: lo_const }
@@ -619,9 +619,9 @@ pub(super) enum Constructor<'tcx> {
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
-    FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd),
+    FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
     /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
-    Str(mir::ConstantKind<'tcx>),
+    Str(mir::Const<'tcx>),
     /// Array and slice patterns.
     Slice(Slice),
     /// Constants that must not be matched structurally. They are treated as black
@@ -1379,8 +1379,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                 let ty = lo.ty();
                 ctor = if let Some(int_range) = IntRange::from_range(
                     cx.tcx,
-                    lo.eval_bits(cx.tcx, cx.param_env, lo.ty()),
-                    hi.eval_bits(cx.tcx, cx.param_env, hi.ty()),
+                    lo.eval_bits(cx.tcx, cx.param_env),
+                    hi.eval_bits(cx.tcx, cx.param_env),
                     ty,
                     &end,
                 ) {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 3d9e634c849..f1f75c26717 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -20,7 +20,7 @@ use rustc_index::Idx;
 use rustc_middle::mir::interpret::{
     ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
 };
-use rustc_middle::mir::{self, ConstantKind, UserTypeProjection};
+use rustc_middle::mir::{self, Const, UserTypeProjection};
 use rustc_middle::mir::{BorrowKind, Mutability};
 use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
@@ -100,8 +100,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     fn lower_pattern_range(
         &mut self,
         ty: Ty<'tcx>,
-        lo: mir::ConstantKind<'tcx>,
-        hi: mir::ConstantKind<'tcx>,
+        lo: mir::Const<'tcx>,
+        hi: mir::Const<'tcx>,
         end: RangeEnd,
         span: Span,
         lo_expr: Option<&hir::Expr<'tcx>>,
@@ -131,7 +131,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
                     && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
                 {
-                    if lo.eval_bits(self.tcx, self.param_env, ty) != val {
+                    if lo.eval_bits(self.tcx, self.param_env) != val {
                         lower_overflow = true;
                         self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
                     }
@@ -139,7 +139,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
                     && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
                 {
-                    if hi.eval_bits(self.tcx, self.param_env, ty) != val {
+                    if hi.eval_bits(self.tcx, self.param_env) != val {
                         higher_overflow = true;
                         self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
                     }
@@ -162,7 +162,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
                     && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
                 {
-                    if lo.eval_bits(self.tcx, self.param_env, ty) != val {
+                    if lo.eval_bits(self.tcx, self.param_env) != val {
                         lower_overflow = true;
                         self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
                     }
@@ -170,7 +170,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
                     && let rustc_ast::ast::LitKind::Int(val, _) = lit.node
                 {
-                    if hi.eval_bits(self.tcx, self.param_env, ty) != val {
+                    if hi.eval_bits(self.tcx, self.param_env) != val {
                         higher_overflow = true;
                         self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
                     }
@@ -191,18 +191,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         ty: Ty<'tcx>,
         lo: Option<&PatKind<'tcx>>,
         hi: Option<&PatKind<'tcx>>,
-    ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> {
+    ) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> {
         match (lo, hi) {
             (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
                 Some((*lo, *hi))
             }
             (Some(PatKind::Constant { value: lo }), None) => {
                 let hi = ty.numeric_max_val(self.tcx)?;
-                Some((*lo, mir::ConstantKind::from_ty_const(hi, self.tcx)))
+                Some((*lo, mir::Const::from_ty_const(hi, self.tcx)))
             }
             (None, Some(PatKind::Constant { value: hi })) => {
                 let lo = ty.numeric_min_val(self.tcx)?;
-                Some((mir::ConstantKind::from_ty_const(lo, self.tcx), *hi))
+                Some((mir::Const::from_ty_const(lo, self.tcx), *hi))
             }
             _ => None,
         }
@@ -525,8 +525,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             .tcx
             .const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span))
             .map(|val| match val {
-                Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
-                None => mir::ConstantKind::Val(
+                Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
+                None => mir::Const::Val(
                     self.tcx
                         .const_eval_global_id(param_env_reveal_all, cid, Some(span))
                         .expect("const_eval_global_id_for_typeck should have already failed"),
@@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         };
         if let Some(lit_input) = lit_input {
             match tcx.at(expr.span).lit_to_const(lit_input) {
-                Ok(c) => return self.const_to_pat(ConstantKind::Ty(c), id, span, None).kind,
+                Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind,
                 // If an error occurred, ignore that it's a literal
                 // and leave reporting the error up to const eval of
                 // the unevaluated constant below.
@@ -632,7 +632,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
         {
             self.const_to_pat(
-                ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
+                Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
                 id,
                 span,
                 None,
@@ -641,7 +641,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         } else {
             // If that fails, convert it to an opaque constant pattern.
             match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
-                Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
+                Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
                 Err(ErrorHandled::TooGeneric(_)) => {
                     // If we land here it means the const can't be evaluated because it's `TooGeneric`.
                     self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
@@ -678,7 +678,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
         match self.tcx.at(expr.span).lit_to_const(lit_input) {
             Ok(constant) => {
-                self.const_to_pat(ConstantKind::Ty(constant), expr.hir_id, lit.span, None).kind
+                self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
             }
             Err(LitToConstError::Reported(_)) => PatKind::Wild,
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
@@ -838,8 +838,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
 #[instrument(skip(tcx), level = "debug")]
 pub(crate) fn compare_const_vals<'tcx>(
     tcx: TyCtxt<'tcx>,
-    a: mir::ConstantKind<'tcx>,
-    b: mir::ConstantKind<'tcx>,
+    a: mir::Const<'tcx>,
+    b: mir::Const<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> Option<Ordering> {
     assert_eq!(a.ty(), b.ty());
@@ -855,18 +855,18 @@ pub(crate) fn compare_const_vals<'tcx>(
         ty::Float(_) | ty::Int(_) => {} // require special handling, see below
         _ => match (a, b) {
             (
-                mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
-                mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
+                mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
+                mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
             ) => return Some(a.cmp(&b)),
-            (mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => {
+            (mir::Const::Ty(a), mir::Const::Ty(b)) => {
                 return Some(a.kind().cmp(&b.kind()));
             }
             _ => {}
         },
     }
 
-    let a = a.eval_bits(tcx, param_env, ty);
-    let b = b.eval_bits(tcx, param_env, ty);
+    let a = a.eval_bits(tcx, param_env);
+    let b = b.eval_bits(tcx, param_env);
 
     use rustc_apfloat::Float;
     match *ty.kind() {
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index ad5f83d9e25..e24685cb90f 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -973,10 +973,10 @@ where
     }
 
     fn constant_usize(&self, val: u16) -> Operand<'tcx> {
-        Operand::Constant(Box::new(Constant {
+        Operand::Constant(Box::new(ConstOperand {
             span: self.source_info.span,
             user_ty: None,
-            literal: ConstantKind::from_usize(self.tcx(), val.into()),
+            const_: Const::from_usize(self.tcx(), val.into()),
         }))
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 775c522b476..1ebb59b3a63 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -190,7 +190,7 @@ impl PeekCall {
         if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
             &terminator.kind
         {
-            if let ty::FnDef(def_id, fn_args) = *func.literal.ty().kind() {
+            if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() {
                 let name = tcx.item_name(def_id);
                 if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
                     return None;
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 514146b5030..dd20e5d7430 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -225,7 +225,7 @@ pub trait ValueAnalysis<'tcx> {
 
     fn handle_constant(
         &self,
-        constant: &Constant<'tcx>,
+        constant: &ConstOperand<'tcx>,
         state: &mut State<Self::Value>,
     ) -> Self::Value {
         self.super_constant(constant, state)
@@ -233,7 +233,7 @@ pub trait ValueAnalysis<'tcx> {
 
     fn super_constant(
         &self,
-        _constant: &Constant<'tcx>,
+        _constant: &ConstOperand<'tcx>,
         _state: &mut State<Self::Value>,
     ) -> Self::Value {
         Self::Value::TOP
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index fe66a9a0994..28765af20ad 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -181,13 +181,10 @@ fn insert_alignment_check<'tcx>(
     // Subtract 1 from the alignment to get the alignment mask
     let alignment_mask =
         local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
-    let one = Operand::Constant(Box::new(Constant {
+    let one = Operand::Constant(Box::new(ConstOperand {
         span: source_info.span,
         user_ty: None,
-        literal: ConstantKind::Val(
-            ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)),
-            tcx.types.usize,
-        ),
+        const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
     }));
     block_data.statements.push(Statement {
         source_info,
@@ -213,13 +210,10 @@ fn insert_alignment_check<'tcx>(
 
     // Check if the alignment bits are all zero
     let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
-    let zero = Operand::Constant(Box::new(Constant {
+    let zero = Operand::Constant(Box::new(ConstOperand {
         span: source_info.span,
         user_ty: None,
-        literal: ConstantKind::Val(
-            ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)),
-            tcx.types.usize,
-        ),
+        const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
     }));
     block_data.statements.push(Statement {
         source_info,
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index d5af321d726..bacabc62ee4 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -142,9 +142,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
 
     fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
         if let Operand::Constant(constant) = op {
-            let maybe_uneval = match constant.literal {
-                ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
-                ConstantKind::Unevaluated(uv, _) => Some(uv),
+            let maybe_uneval = match constant.const_ {
+                Const::Val(..) | Const::Ty(_) => None,
+                Const::Unevaluated(uv, _) => Some(uv),
             };
 
             if let Some(uv) = maybe_uneval {
diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs
index f662ce645b0..40cd2825408 100644
--- a/compiler/rustc_mir_transform/src/const_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs
@@ -4,7 +4,7 @@
 use rustc_middle::{
     mir::{
         visit::{PlaceContext, Visitor},
-        Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
+        Body, ConstOperand, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
     },
     ty::TyCtxt,
 };
@@ -45,7 +45,7 @@ struct LocalUseVisitor {
     local_assignment_locations: IndexVec<Local, Option<Location>>,
 }
 
-fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> {
+fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, ConstOperand<'tcx>)> {
     let mut visitor = LocalUseVisitor {
         local_mutating_uses: IndexVec::from_elem(0, &body.local_decls),
         local_assignment_locations: IndexVec::from_elem(None, &body.local_decls),
diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs
index e175f22d7a9..fd2d37dbea5 100644
--- a/compiler/rustc_mir_transform/src/const_goto.rs
+++ b/compiler/rustc_mir_transform/src/const_goto.rs
@@ -96,10 +96,10 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
                 let (discr, targets) = target_bb_terminator.kind.as_switch()?;
                 if discr.place() == Some(*place) {
                     let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty;
+                    debug_assert_eq!(switch_ty, _const.ty());
                     // We now know that the Switch matches on the const place, and it is statementless
                     // Now find which value in the Switch matches the const value.
-                    let const_value =
-                        _const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?;
+                    let const_value = _const.const_.try_eval_bits(self.tcx, self.param_env)?;
                     let target_to_use_in_goto = targets.target_for_value(const_value);
                     self.optimizations.push(OptimizationToApply {
                         bb_with_goto: location.block,
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index c6aac2ca213..4fc78b28580 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -210,7 +210,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _bin_op: BinOp,
         _left: &ImmTy<'tcx>,
         _right: &ImmTy<'tcx>,
-    ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> {
         // We can't do this because aliasing of memory can differ between const eval and llvm
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
@@ -525,7 +525,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<ConstantKind<'tcx>> {
+    fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Const<'tcx>> {
         // This will return None if the above `const_prop` invocation only "wrote" a
         // type whose creation requires no write. E.g. a generator whose initial state
         // consists solely of uninitialized memory (so it doesn't capture any locals).
@@ -541,7 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         let Right(imm) = imm else { return None };
         match *imm {
             Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
-                Some(ConstantKind::from_scalar(self.tcx, scalar, value.layout.ty))
+                Some(Const::from_scalar(self.tcx, scalar, value.layout.ty))
             }
             Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
                 let alloc_id = self
@@ -551,7 +551,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     })
                     .ok()?;
 
-                Some(ConstantKind::Val(
+                Some(Const::Val(
                     ConstValue::Indirect { alloc_id, offset: Size::ZERO },
                     value.layout.ty,
                 ))
@@ -731,7 +731,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
                 if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) {
                     // If this was already an evaluated constant, keep it.
                     if let Rvalue::Use(Operand::Constant(c)) = rvalue
-                        && let ConstantKind::Val(..) = c.literal
+                        && let Const::Val(..) = c.const_
                     {
                         trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
                     } else if let Some(operand) = self.replace_with_const(*place) {
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index fb33b3b49d3..64e262c6c93 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -281,7 +281,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     }
 
     /// Returns the value, if any, of evaluating `c`.
-    fn eval_constant(&mut self, c: &Constant<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
+    fn eval_constant(&mut self, c: &ConstOperand<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
         // FIXME we need to revisit this for #67176
         if c.has_param() {
             return None;
@@ -293,7 +293,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         // that the `RevealAll` pass has happened and that the body's consts
         // are normalized, so any call to resolve before that needs to be
         // manually normalized.
-        let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.literal).ok()?;
+        let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?;
 
         self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None))
     }
@@ -322,7 +322,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> {
         if let (val, true) = self.use_ecx(location, |this| {
             let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
-            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?;
+            let (_res, overflow) = this.ecx.overflowing_unary_op(op, &val)?;
             Ok((val, overflow))
         })? {
             // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
@@ -390,7 +390,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         if let (Some(l), Some(r)) = (l, r) {
             // The remaining operators are handled through `overflowing_binary_op`.
             if self.use_ecx(location, |this| {
-                let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
+                let (_res, overflow) = this.ecx.overflowing_binary_op(op, &l, &r)?;
                 Ok(overflow)
             })? {
                 let source_info = self.body().source_info(location);
@@ -580,7 +580,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
         self.super_operand(operand, location);
     }
 
-    fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
+    fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
         trace!("visit_constant: {:?}", constant);
         self.super_constant(constant, location);
         self.eval_constant(constant, location);
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index cf827c98894..7b14fef6153 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -206,7 +206,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     && let operand_ty = operand.ty(self.local_decls, self.tcx)
                     && let Some(operand_ty) = operand_ty.builtin_deref(true)
                     && let ty::Array(_, len) = operand_ty.ty.kind()
-                    && let Some(len) = ConstantKind::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
+                    && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
                 {
                     state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
                 }
@@ -224,7 +224,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
             Rvalue::Len(place) => {
                 let place_ty = place.ty(self.local_decls, self.tcx);
                 if let ty::Array(_, len) = place_ty.ty.kind() {
-                    ConstantKind::Ty(*len)
+                    Const::Ty(*len)
                         .try_eval_scalar(self.tcx, self.param_env)
                         .map_or(FlatSet::Top, FlatSet::Elem)
                 } else if let [ProjectionElem::Deref] = place.projection[..] {
@@ -234,21 +234,27 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 }
             }
             Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
+                let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
+                    return ValueOrPlace::Value(FlatSet::Top);
+                };
                 match self.eval_operand(operand, state) {
                     FlatSet::Elem(op) => self
                         .ecx
-                        .int_to_int_or_float(&op, *ty)
-                        .map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
+                        .int_to_int_or_float(&op, layout)
+                        .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
                     FlatSet::Bottom => FlatSet::Bottom,
                     FlatSet::Top => FlatSet::Top,
                 }
             }
             Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => {
+                let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
+                    return ValueOrPlace::Value(FlatSet::Top);
+                };
                 match self.eval_operand(operand, state) {
                     FlatSet::Elem(op) => self
                         .ecx
-                        .float_to_float_or_int(&op, *ty)
-                        .map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
+                        .float_to_float_or_int(&op, layout)
+                        .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
                     FlatSet::Bottom => FlatSet::Bottom,
                     FlatSet::Top => FlatSet::Top,
                 }
@@ -268,7 +274,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
             Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
                 FlatSet::Elem(value) => self
                     .ecx
-                    .unary_op(*op, &value)
+                    .wrapping_unary_op(*op, &value)
                     .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)),
                 FlatSet::Bottom => FlatSet::Bottom,
                 FlatSet::Top => FlatSet::Top,
@@ -295,11 +301,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
 
     fn handle_constant(
         &self,
-        constant: &Constant<'tcx>,
+        constant: &ConstOperand<'tcx>,
         _state: &mut State<Self::Value>,
     ) -> Self::Value {
         constant
-            .literal
+            .const_
             .try_eval_scalar(self.tcx, self.param_env)
             .map_or(FlatSet::Top, FlatSet::Elem)
     }
@@ -360,7 +366,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 }
             }
             Operand::Constant(box constant) => {
-                if let Ok(constant) = self.ecx.eval_mir_constant(&constant.literal, None, None) {
+                if let Ok(constant) = self.ecx.eval_mir_constant(&constant.const_, None, None) {
                     self.assign_constant(state, place, constant, &[]);
                 }
             }
@@ -439,7 +445,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             // Both sides are known, do the actual computation.
             (FlatSet::Elem(left), FlatSet::Elem(right)) => {
                 match self.ecx.overflowing_binary_op(op, &left, &right) {
-                    Ok((val, overflow, _)) => (FlatSet::Elem(val), FlatSet::Elem(overflow)),
+                    Ok((val, overflow)) => {
+                        (FlatSet::Elem(val.to_scalar()), FlatSet::Elem(overflow))
+                    }
                     _ => (FlatSet::Top, FlatSet::Top),
                 }
             }
@@ -518,10 +526,10 @@ pub(crate) struct Patch<'tcx> {
     /// For a given MIR location, this stores the values of the operands used by that location. In
     /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
     /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
-    pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), ConstantKind<'tcx>>,
+    pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>,
 
     /// Stores the assigned values for assignments where the Rvalue is constant.
-    pub(crate) assignments: FxHashMap<Location, ConstantKind<'tcx>>,
+    pub(crate) assignments: FxHashMap<Location, Const<'tcx>>,
 }
 
 impl<'tcx> Patch<'tcx> {
@@ -529,8 +537,8 @@ impl<'tcx> Patch<'tcx> {
         Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
     }
 
-    fn make_operand(&self, literal: ConstantKind<'tcx>) -> Operand<'tcx> {
-        Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, literal }))
+    fn make_operand(&self, const_: Const<'tcx>) -> Operand<'tcx> {
+        Operand::Constant(Box::new(ConstOperand { span: DUMMY_SP, user_ty: None, const_ }))
     }
 }
 
@@ -549,12 +557,12 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
         place: Place<'tcx>,
         state: &State<FlatSet<Scalar>>,
         map: &Map,
-    ) -> Option<ConstantKind<'tcx>> {
+    ) -> Option<Const<'tcx>> {
         let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
             return None;
         };
         let ty = place.ty(self.local_decls, self.patch.tcx).ty;
-        Some(ConstantKind::Val(ConstValue::Scalar(value.into()), ty))
+        Some(Const::Val(ConstValue::Scalar(value.into()), ty))
     }
 }
 
@@ -783,8 +791,8 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         _bin_op: BinOp,
         _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
         _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
-    ) -> interpret::InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)> {
-        throw_unsup!(Unsupported("".into()))
+    ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
+        crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic");
     }
 
     fn expose_ptr(
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index 909116a77f5..666293cbc30 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -150,7 +150,7 @@ fn rvalue_hash<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'_>) {
 
 fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'_>) {
     match operand {
-        Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher),
+        Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }) => const_.hash(hasher),
         x => x.hash(hasher),
     };
 }
@@ -179,9 +179,9 @@ fn rvalue_eq<'tcx>(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool {
 fn operand_eq<'tcx>(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool {
     let res = match (lhs, rhs) {
         (
-            Operand::Constant(box Constant { user_ty: _, literal, span: _ }),
-            Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }),
-        ) => literal == literal2,
+            Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }),
+            Operand::Constant(box ConstOperand { user_ty: _, const_: const2, span: _ }),
+        ) => const_ == const2,
         (x, y) => x == y,
     };
     debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 78d7ffb3698..6a89d067275 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -402,10 +402,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     }
 
     fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
-        Rvalue::Use(Operand::Constant(Box::new(Constant {
+        Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
             span,
             user_ty: None,
-            literal: ConstantKind::from_bool(self.tcx, val),
+            const_: Const::from_bool(self.tcx, val),
         })))
     }
 
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index eae83448c46..96c60fdf41b 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1189,10 +1189,10 @@ fn insert_panic_block<'tcx>(
 ) -> BasicBlock {
     let assert_block = BasicBlock::new(body.basic_blocks.len());
     let term = TerminatorKind::Assert {
-        cond: Operand::Constant(Box::new(Constant {
+        cond: Operand::Constant(Box::new(ConstOperand {
             span: body.span,
             user_ty: None,
-            literal: ConstantKind::from_bool(tcx, false),
+            const_: Const::from_bool(tcx, false),
         })),
         expected: true,
         msg: Box::new(message),
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 4dc7c3b6444..1d9c89477cb 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -652,11 +652,11 @@ impl<'tcx> Inliner<'tcx> {
                 // `required_consts`, here we may not only have `ConstKind::Unevaluated`
                 // because we are calling `subst_and_normalize_erasing_regions`.
                 caller_body.required_consts.extend(
-                    callee_body.required_consts.iter().copied().filter(|&ct| match ct.literal {
-                        ConstantKind::Ty(_) => {
+                    callee_body.required_consts.iter().copied().filter(|&ct| match ct.const_ {
+                        Const::Ty(_) => {
                             bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
                         }
-                        ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => true,
+                        Const::Val(..) | Const::Unevaluated(..) => true,
                     }),
                 );
             }
@@ -824,7 +824,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
                 }
             }
             TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
-                let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.literal.ty()));
+                let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty()));
                 self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
                     // Don't give intrinsics the extra penalty for calls
                     INSTR_COST
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 6e191b285be..a6ef2e11aa8 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -104,7 +104,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
 
     fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> {
         let a = a.constant()?;
-        if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None }
+        if a.const_.ty().is_bool() { a.const_.try_to_bool() } else { None }
     }
 
     /// Transform "&(*a)" ==> "a".
@@ -136,8 +136,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
                     return;
                 }
 
-                let literal = ConstantKind::from_ty_const(len, self.tcx);
-                let constant = Constant { span: source_info.span, literal, user_ty: None };
+                let const_ = Const::from_ty_const(len, self.tcx);
+                let constant = ConstOperand { span: source_info.span, const_, user_ty: None };
                 *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
             }
         }
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index fc49c9ba348..4eee45f8d00 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -149,10 +149,10 @@ impl EnumSizeOpt {
                     };
 
                     let place = Place::from(size_array_local);
-                    let constant_vals = Constant {
+                    let constant_vals = ConstOperand {
                         span,
                         user_ty: None,
-                        literal: ConstantKind::Val(
+                        const_: Const::Val(
                             ConstValue::Indirect { alloc_id, offset: Size::ZERO },
                             tmp_ty,
                         ),
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 70d4ea74d1a..d55b0cbe635 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -31,9 +31,9 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{
-    traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstQualifs, Constant, LocalDecl,
-    MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
-    Statement, StatementKind, TerminatorKind, START_BLOCK,
+    traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs,
+    LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue,
+    SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK,
 };
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
@@ -149,14 +149,14 @@ fn remap_mir_for_const_eval_select<'tcx>(
         let terminator = bb.terminator.as_mut().expect("invalid terminator");
         match terminator.kind {
             TerminatorKind::Call {
-                func: Operand::Constant(box Constant { ref literal, .. }),
+                func: Operand::Constant(box ConstOperand { ref const_, .. }),
                 ref mut args,
                 destination,
                 target,
                 unwind,
                 fn_span,
                 ..
-            } if let ty::FnDef(def_id, _) = *literal.ty().kind()
+            } if let ty::FnDef(def_id, _) = *const_.ty().kind()
                 && tcx.item_name(def_id) == sym::const_eval_select
                 && tcx.is_intrinsic(def_id) =>
             {
@@ -343,7 +343,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
     let body = match tcx.hir().body_const_context(def) {
         // consts and statics do not have `optimized_mir`, so we can steal the body instead of
         // cloning it.
-        Some(hir::ConstContext::Const | hir::ConstContext::Static(_)) => body.steal(),
+        Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(),
         Some(hir::ConstContext::ConstFn) => body.borrow().clone(),
         None => bug!("`mir_for_ctfe` called on non-const {def:?}"),
     };
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 13277d62bf4..0d2d764c422 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -32,10 +32,10 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
                                     *destination,
-                                    Rvalue::Use(Operand::Constant(Box::new(Constant {
+                                    Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
                                         span: terminator.source_info.span,
                                         user_ty: None,
-                                        literal: ConstantKind::zero_sized(tcx.types.unit),
+                                        const_: Const::zero_sized(tcx.types.unit),
                                     }))),
                                 ))),
                             });
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index bc29fb8ded1..3dc627b6146 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -98,10 +98,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                         StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
                     ) if lhs_f == lhs_s
-                        && f_c.literal.ty().is_bool()
-                        && s_c.literal.ty().is_bool()
-                        && f_c.literal.try_eval_bool(tcx, param_env).is_some()
-                        && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {}
+                        && f_c.const_.ty().is_bool()
+                        && s_c.const_.ty().is_bool()
+                        && f_c.const_.try_eval_bool(tcx, param_env).is_some()
+                        && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {}
 
                     // Otherwise we cannot optimize. Try another block.
                     _ => continue 'outer,
@@ -128,8 +128,8 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                         StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
                     ) => {
                         // From earlier loop we know that we are dealing with bool constants only:
-                        let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap();
-                        let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
+                        let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap();
+                        let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap();
                         if f_b == s_b {
                             // Same value in both blocks. Use statement as is.
                             (*f).clone()
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index 1b846987d38..d1a4b26a046 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -90,10 +90,10 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
             && let [PlaceElem::Deref] = &place.projection[..]
             && let Some(len) = self.slice_lengths[place.local]
         {
-            *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant {
+            *rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
                 span: rustc_span::DUMMY_SP,
                 user_ty: None,
-                literal: ConstantKind::from_ty_const(len, self.tcx),
+                const_: Const::from_ty_const(len, self.tcx),
             })));
         }
         self.super_rvalue(rvalue, loc);
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index dcc4cd85cda..a34d4b02764 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -62,12 +62,12 @@ impl<'tcx> Replacer<'_, 'tcx> {
         layout.is_zst()
     }
 
-    fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> {
+    fn make_zst(&self, ty: Ty<'tcx>) -> ConstOperand<'tcx> {
         debug_assert!(self.known_to_be_zst(ty));
-        Constant {
+        ConstOperand {
             span: rustc_span::DUMMY_SP,
             user_ty: None,
-            literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
+            const_: Const::Val(ConstValue::ZeroSized, ty),
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs
index 243cb463560..abde6a47e83 100644
--- a/compiler/rustc_mir_transform/src/required_consts.rs
+++ b/compiler/rustc_mir_transform/src/required_consts.rs
@@ -1,27 +1,27 @@
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{Constant, ConstantKind, Location};
+use rustc_middle::mir::{Const, ConstOperand, Location};
 use rustc_middle::ty::ConstKind;
 
 pub struct RequiredConstsVisitor<'a, 'tcx> {
-    required_consts: &'a mut Vec<Constant<'tcx>>,
+    required_consts: &'a mut Vec<ConstOperand<'tcx>>,
 }
 
 impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
-    pub fn new(required_consts: &'a mut Vec<Constant<'tcx>>) -> Self {
+    pub fn new(required_consts: &'a mut Vec<ConstOperand<'tcx>>) -> Self {
         RequiredConstsVisitor { required_consts }
     }
 }
 
 impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
-    fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
-        let literal = constant.literal;
-        match literal {
-            ConstantKind::Ty(c) => match c.kind() {
+    fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) {
+        let const_ = constant.const_;
+        match const_ {
+            Const::Ty(c) => match c.kind() {
                 ConstKind::Param(_) | ConstKind::Error(_) | ConstKind::Value(_) => {}
                 _ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c),
             },
-            ConstantKind::Unevaluated(..) => self.required_consts.push(*constant),
-            ConstantKind::Val(..) => {}
+            Const::Unevaluated(..) => self.required_consts.push(*constant),
+            Const::Val(..) => {}
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index 23442f8b97b..065793348e4 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -35,12 +35,12 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
     }
 
     #[inline]
-    fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _: Location) {
+    fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _: Location) {
         // We have to use `try_normalize_erasing_regions` here, since it's
         // possible that we visit impossible-to-satisfy where clauses here,
         // see #91745
-        if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.literal) {
-            constant.literal = c;
+        if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) {
+            constant.const_ = c;
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index e1000d96932..e9895d97dfe 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -497,10 +497,10 @@ impl<'tcx> CloneShimBuilder<'tcx> {
 
         // `func == Clone::clone(&ty) -> ty`
         let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]);
-        let func = Operand::Constant(Box::new(Constant {
+        let func = Operand::Constant(Box::new(ConstOperand {
             span: self.span,
             user_ty: None,
-            literal: ConstantKind::zero_sized(func_ty),
+            const_: Const::zero_sized(func_ty),
         }));
 
         let ref_loc = self.make_place(
@@ -764,10 +764,10 @@ fn build_call_shim<'tcx>(
         CallKind::Direct(def_id) => {
             let ty = tcx.type_of(def_id).instantiate_identity();
             (
-                Operand::Constant(Box::new(Constant {
+                Operand::Constant(Box::new(ConstOperand {
                     span,
                     user_ty: None,
-                    literal: ConstantKind::zero_sized(ty),
+                    const_: Const::zero_sized(ty),
                 })),
                 rcvr.into_iter().collect::<Vec<_>>(),
             )
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index 1ff48816986..b508cd1c9cc 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -23,7 +23,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
                 TerminatorKind::SwitchInt {
                     discr: Operand::Constant(ref c), ref targets, ..
                 } => {
-                    let constant = c.literal.try_eval_bits(tcx, param_env, c.ty());
+                    let constant = c.const_.try_eval_bits(tcx, param_env);
                     if let Some(constant) = constant {
                         let target = targets.target_for_value(constant);
                         TerminatorKind::Goto { target }
@@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
                 }
                 TerminatorKind::Assert {
                     target, cond: Operand::Constant(ref c), expected, ..
-                } => match c.literal.try_eval_bool(tcx, param_env) {
+                } => match c.const_.try_eval_bool(tcx, param_env) {
                     Some(v) if v == expected => TerminatorKind::Goto { target },
                     _ => continue,
                 },
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index 113ca2fc5ad..1a8cfc41178 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -206,12 +206,12 @@ fn find_branch_value_info<'tcx>(
     match (left, right) {
         (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on))
         | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => {
-            let branch_value_ty = branch_value.literal.ty();
+            let branch_value_ty = branch_value.const_.ty();
             // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats
             if !branch_value_ty.is_integral() && !branch_value_ty.is_char() {
                 return None;
             };
-            let branch_value_scalar = branch_value.literal.try_to_scalar()?;
+            let branch_value_scalar = branch_value.const_.try_to_scalar()?;
             Some((branch_value_scalar, branch_value_ty, *to_switch_on))
         }
         _ => None,
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index c8b72107756..4afa4e597f7 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -746,20 +746,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
     /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
     /// work, as some constants cannot be represented in the type system.
     #[instrument(skip(self), level = "debug")]
-    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
-        let literal = self.monomorphize(constant.literal);
+    fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) {
+        let const_ = self.monomorphize(constant.const_);
         let param_env = ty::ParamEnv::reveal_all();
-        let val = match literal.eval(self.tcx, param_env, None) {
+        let val = match const_.eval(self.tcx, param_env, None) {
             Ok(v) => v,
             Err(ErrorHandled::Reported(..)) => return,
             Err(ErrorHandled::TooGeneric(..)) => span_bug!(
                 self.body.source_info(location).span,
                 "collection encountered polymorphic constant: {:?}",
-                literal
+                const_
             ),
         };
         collect_const_value(self.tcx, val, self.output);
-        MirVisitor::visit_ty(self, literal.ty(), TyContext::Location(location));
+        MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location));
     }
 
     fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
@@ -796,7 +796,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 for op in operands {
                     match *op {
                         mir::InlineAsmOperand::SymFn { ref value } => {
-                            let fn_ty = self.monomorphize(value.literal.ty());
+                            let fn_ty = self.monomorphize(value.const_.ty());
                             visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]);
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index a8b7a0dbb68..0e85f35fc1b 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -9,13 +9,13 @@ use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
 use rustc_middle::mir::{
     self,
     visit::{TyContext, Visitor},
-    Constant, ConstantKind, Local, LocalDecl, Location,
+    Local, LocalDecl, Location,
 };
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
     self,
     visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor},
-    Const, GenericArgsRef, Ty, TyCtxt, UnusedGenericParams,
+    GenericArgsRef, Ty, TyCtxt, UnusedGenericParams,
 };
 use rustc_span::symbol::sym;
 use std::ops::ControlFlow;
@@ -261,12 +261,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
         self.super_local_decl(local, local_decl);
     }
 
-    fn visit_constant(&mut self, ct: &Constant<'tcx>, location: Location) {
-        match ct.literal {
-            ConstantKind::Ty(c) => {
+    fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) {
+        match ct.const_ {
+            mir::Const::Ty(c) => {
                 c.visit_with(self);
             }
-            ConstantKind::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => {
+            mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => {
                 // Avoid considering `T` unused when constants are of the form:
                 //   `<Self as Foo<T>>::foo::promoted[p]`
                 if let Some(p) = promoted {
@@ -280,7 +280,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
 
                 Visitor::visit_ty(self, ty, TyContext::Location(location));
             }
-            ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
+            mir::Const::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
         }
     }
 
@@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
 
 impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
-    fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.has_non_region_param() {
             return ControlFlow::Continue(());
         }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 4f8ce99417a..dc0776c5dad 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -407,6 +407,10 @@ passes_invalid_stability =
     .label = invalid stability version
     .item = the stability attribute annotates this item
 
+passes_lang_item_fn_with_target_feature =
+    `{$name}` language item function is not allowed to have `#[target_feature]`
+    .label = `{$name}` language item function is not allowed to have `#[target_feature]`
+
 passes_lang_item_on_incorrect_target =
     `{$name}` language item must be applied to a {$expected_target}
     .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2d94354e3e1..12118a0268b 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -118,7 +118,7 @@ impl CheckAttrVisitor<'_> {
                 sym::coverage => self.check_coverage(hir_id, attr, span, target),
                 sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
                 sym::marker => self.check_marker(hir_id, attr, span, target),
-                sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
+                sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs),
                 sym::thread_local => self.check_thread_local(attr, span, target),
                 sym::track_caller => {
                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
@@ -591,10 +591,36 @@ impl CheckAttrVisitor<'_> {
         attr: &Attribute,
         span: Span,
         target: Target,
+        attrs: &[Attribute],
     ) -> bool {
         match target {
-            Target::Fn
-            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+            Target::Fn => {
+                // `#[target_feature]` is not allowed in language items.
+                if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
+                    // Calling functions with `#[target_feature]` is
+                    // not unsafe on WASM, see #84988
+                    && !self.tcx.sess.target.is_like_wasm
+                    && !self.tcx.sess.opts.actually_rustdoc
+                {
+                    let hir::Node::Item(item) = self.tcx.hir().get(hir_id) else {
+                        unreachable!();
+                    };
+                    let hir::ItemKind::Fn(sig, _, _) = item.kind else {
+                        // target is `Fn`
+                        unreachable!();
+                    };
+
+                    self.tcx.sess.emit_err(errors::LangItemWithTargetFeature {
+                        attr_span: attr.span,
+                        name: lang_item,
+                        sig_span: sig.span,
+                    });
+                    false
+                } else {
+                    true
+                }
+            }
+            Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
             // FIXME: #[target_feature] was previously erroneously allowed on statements and some
             // crates used this, so only emit a warning.
             Target::Statement => {
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 8437e9a40e2..6d176af8098 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -193,12 +193,12 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
     }
 
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
-        let kind = Some(hir::ConstContext::Const);
+        let kind = Some(hir::ConstContext::Const { inline: false });
         self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
     }
 
     fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) {
-        let kind = Some(hir::ConstContext::Const);
+        let kind = Some(hir::ConstContext::Const { inline: true });
         self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block));
     }
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 8b65e301b74..2ec6a0b9241 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -809,6 +809,16 @@ pub struct MissingLangItem {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_lang_item_fn_with_target_feature)]
+pub struct LangItemWithTargetFeature {
+    #[primary_span]
+    pub attr_span: Span,
+    pub name: Symbol,
+    #[label]
+    pub sig_span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_lang_item_on_incorrect_target, code = "E0718")]
 pub struct LangItemOnIncorrectTarget {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 476394f30cc..7e837243918 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -20,7 +20,8 @@ use rustc_hir::lang_items::{extract, GenericRequirement};
 use rustc_hir::{LangItem, LanguageItems, Target};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::ExternCrate;
-use rustc_span::{symbol::kw::Empty, Span};
+use rustc_span::symbol::kw::Empty;
+use rustc_span::{sym, Span};
 
 use rustc_middle::query::Providers;
 
@@ -157,7 +158,14 @@ impl<'tcx> LanguageItemCollector<'tcx> {
             self.tcx.hir().get_by_def_id(item_def_id)
         {
             let (actual_num, generics_span) = match kind.generics() {
-                Some(generics) => (generics.params.len(), generics.span),
+                Some(generics) => (
+                    generics
+                        .params
+                        .iter()
+                        .filter(|p| !self.tcx.has_attr(p.def_id, sym::rustc_host))
+                        .count(),
+                    generics.span,
+                ),
                 None => (0, *item_span),
             };
 
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 9a0fcbb37a7..30621a135eb 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -92,7 +92,7 @@ where
     }
 
     #[inline(always)]
-    fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, DepKind>
+    fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key>
     where
         QueryCtxt<'tcx>: 'a,
     {
@@ -145,7 +145,7 @@ where
     fn value_from_cycle_error(
         self,
         tcx: TyCtxt<'tcx>,
-        cycle: &[QueryInfo<DepKind>],
+        cycle: &[QueryInfo],
         guar: ErrorGuaranteed,
     ) -> Self::Value {
         (self.dynamic.value_from_cycle_error)(tcx, cycle, guar)
@@ -198,6 +198,8 @@ trait QueryConfigRestored<'tcx> {
     type RestoredValue;
     type Config: QueryConfig<QueryCtxt<'tcx>>;
 
+    const NAME: &'static &'static str;
+
     fn config(tcx: TyCtxt<'tcx>) -> Self::Config;
     fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value)
     -> Self::RestoredValue;
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index f2fdf066d15..4516708ce17 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -8,7 +8,9 @@ use crate::QueryConfigRestored;
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_data_structures::sync::Lock;
 use rustc_errors::Diagnostic;
+
 use rustc_index::Idx;
+use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::dep_graph::{
     self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
 };
@@ -53,7 +55,7 @@ impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
 }
 
 impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
-    type DepKind = rustc_middle::dep_graph::DepKind;
+    type Deps = rustc_middle::dep_graph::DepsType;
     type DepContext = TyCtxt<'tcx>;
 
     #[inline]
@@ -78,7 +80,7 @@ impl QueryContext for QueryCtxt<'_> {
         tls::with_related_context(self.tcx, |icx| icx.query)
     }
 
-    fn try_collect_active_jobs(self) -> Option<QueryMap<DepKind>> {
+    fn try_collect_active_jobs(self) -> Option<QueryMap> {
         let mut jobs = QueryMap::default();
 
         for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() {
@@ -154,7 +156,7 @@ impl QueryContext for QueryCtxt<'_> {
         let mut span = None;
         let mut layout_of_depth = None;
         if let Some(map) = self.try_collect_active_jobs() {
-            if let Some((info, depth)) = job.try_find_layout_root(map) {
+            if let Some((info, depth)) = job.try_find_layout_root(map, dep_kinds::layout_of) {
                 span = Some(info.job.span);
                 layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth });
             }
@@ -300,7 +302,7 @@ pub(crate) fn create_query_frame<
     key: K,
     kind: DepKind,
     name: &'static str,
-) -> QueryStackFrame<DepKind> {
+) -> QueryStackFrame {
     // Avoid calling queries while formatting the description
     let description = ty::print::with_no_queries!(
         // Disable visible paths printing for performance reasons.
@@ -312,7 +314,7 @@ pub(crate) fn create_query_frame<
     );
     let description =
         if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description };
-    let span = if kind == dep_graph::DepKind::def_span || with_no_queries() {
+    let span = if kind == dep_graph::dep_kinds::def_span || with_no_queries() {
         // The `def_span` query is used to calculate `default_span`,
         // so exit to avoid infinite recursion.
         None
@@ -320,7 +322,7 @@ pub(crate) fn create_query_frame<
         Some(key.default_span(tcx))
     };
     let def_id = key.key_as_def_id();
-    let def_kind = if kind == dep_graph::DepKind::opt_def_kind || with_no_queries() {
+    let def_kind = if kind == dep_graph::dep_kinds::opt_def_kind || with_no_queries() {
         // Try to avoid infinite recursion.
         None
     } else {
@@ -329,7 +331,7 @@ pub(crate) fn create_query_frame<
     let hash = || {
         tcx.with_stable_hashing_context(|mut hcx| {
             let mut hasher = StableHasher::new();
-            std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher);
+            kind.as_usize().hash_stable(&mut hcx, &mut hasher);
             key.hash_stable(&mut hcx, &mut hasher);
             hasher.finish::<Hash64>()
         })
@@ -430,8 +432,8 @@ where
     // hit the cache instead of having to go through `force_from_dep_node`.
     // This assertion makes sure, we actually keep applying the solution above.
     debug_assert!(
-        dep_node.kind != DepKind::codegen_unit,
-        "calling force_from_dep_node() on DepKind::codegen_unit"
+        dep_node.kind != dep_kinds::codegen_unit,
+        "calling force_from_dep_node() on dep_kinds::codegen_unit"
     );
 
     if let Some(key) = Q::Key::recover(tcx, &dep_node) {
@@ -457,6 +459,7 @@ where
             fingerprint_style,
             force_from_dep_node: None,
             try_load_from_on_disk_cache: None,
+            name: Q::NAME,
         };
     }
 
@@ -470,6 +473,7 @@ where
         try_load_from_on_disk_cache: Some(|tcx, dep_node| {
             try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node)
         }),
+        name: Q::NAME,
     }
 }
 
@@ -565,7 +569,7 @@ macro_rules! define_queries {
                 DynamicQuery {
                     name: stringify!($name),
                     eval_always: is_eval_always!([$($modifiers)*]),
-                    dep_kind: dep_graph::DepKind::$name,
+                    dep_kind: dep_graph::dep_kinds::$name,
                     handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
                     query_state: offset_of!(QueryStates<'tcx> => $name),
                     query_cache: offset_of!(QueryCaches<'tcx> => $name),
@@ -636,6 +640,8 @@ macro_rules! define_queries {
                     { feedable!([$($modifiers)*]) },
                 >;
 
+                const NAME: &'static &'static str = &stringify!($name);
+
                 #[inline(always)]
                 fn config(tcx: TyCtxt<'tcx>) -> Self::Config {
                     DynamicConfig {
@@ -649,9 +655,9 @@ macro_rules! define_queries {
                 }
             }
 
-            pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap<DepKind>) {
+            pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) {
                 let make_query = |tcx, key| {
-                    let kind = rustc_middle::dep_graph::DepKind::$name;
+                    let kind = rustc_middle::dep_graph::dep_kinds::$name;
                     let name = stringify!($name);
                     $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
                 };
@@ -709,7 +715,7 @@ macro_rules! define_queries {
 
         // These arrays are used for iteration and can't be indexed by `DepKind`.
 
-        const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>)] =
+        const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap)] =
             &[$(query_impl::$name::try_collect_active_jobs),*];
 
         const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[
@@ -737,6 +743,7 @@ macro_rules! define_queries {
                     fingerprint_style: FingerprintStyle::Unit,
                     force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
                     try_load_from_on_disk_cache: None,
+                    name: &"Null",
                 }
             }
 
@@ -748,6 +755,7 @@ macro_rules! define_queries {
                     fingerprint_style: FingerprintStyle::Unit,
                     force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
                     try_load_from_on_disk_cache: None,
+                    name: &"Red",
                 }
             }
 
@@ -758,6 +766,7 @@ macro_rules! define_queries {
                     fingerprint_style: FingerprintStyle::Unit,
                     force_from_dep_node: None,
                     try_load_from_on_disk_cache: None,
+                    name: &"TraitSelect",
                 }
             }
 
@@ -768,6 +777,7 @@ macro_rules! define_queries {
                     fingerprint_style: FingerprintStyle::Opaque,
                     force_from_dep_node: None,
                     try_load_from_on_disk_cache: None,
+                    name: &"CompileCodegenUnit",
                 }
             }
 
@@ -778,6 +788,7 @@ macro_rules! define_queries {
                     fingerprint_style: FingerprintStyle::Opaque,
                     force_from_dep_node: None,
                     try_load_from_on_disk_cache: None,
+                    name: &"CompileMonoItem",
                 }
             }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs
index c2c9600f555..103a6c01bd2 100644
--- a/compiler/rustc_query_system/src/dep_graph/debug.rs
+++ b/compiler/rustc_query_system/src/dep_graph/debug.rs
@@ -1,6 +1,6 @@
 //! Code for debugging the dep-graph.
 
-use super::{DepKind, DepNode, DepNodeIndex};
+use super::{DepNode, DepNodeIndex};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 use std::error::Error;
@@ -28,7 +28,7 @@ impl DepNodeFilter {
     }
 
     /// Tests whether `node` meets the filter, returning true if so.
-    pub fn test<K: DepKind>(&self, node: &DepNode<K>) -> bool {
+    pub fn test(&self, node: &DepNode) -> bool {
         let debug_str = format!("{node:?}");
         self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f))
     }
@@ -36,14 +36,14 @@ impl DepNodeFilter {
 
 /// A filter like `F -> G` where `F` and `G` are valid dep-node
 /// filters. This can be used to test the source/target independently.
-pub struct EdgeFilter<K: DepKind> {
+pub struct EdgeFilter {
     pub source: DepNodeFilter,
     pub target: DepNodeFilter,
-    pub index_to_node: Lock<FxHashMap<DepNodeIndex, DepNode<K>>>,
+    pub index_to_node: Lock<FxHashMap<DepNodeIndex, DepNode>>,
 }
 
-impl<K: DepKind> EdgeFilter<K> {
-    pub fn new(test: &str) -> Result<EdgeFilter<K>, Box<dyn Error>> {
+impl EdgeFilter {
+    pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> {
         let parts: Vec<_> = test.split("->").collect();
         if parts.len() != 2 {
             Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
@@ -57,7 +57,7 @@ impl<K: DepKind> EdgeFilter<K> {
     }
 
     #[cfg(debug_assertions)]
-    pub fn test(&self, source: &DepNode<K>, target: &DepNode<K>) -> bool {
+    pub fn test(&self, source: &DepNode, target: &DepNode) -> bool {
         self.source.test(source) && self.target.test(target)
     }
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index 39a4cb1b179..17f96896a50 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -42,36 +42,84 @@
 //!   `DefId` it was computed from. In other cases, too much information gets
 //!   lost during fingerprint computation.
 
-use super::{DepContext, DepKind, FingerprintStyle};
+use super::{DepContext, FingerprintStyle};
 use crate::ich::StableHashingContext;
 
 use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
+use rustc_data_structures::AtomicRef;
 use rustc_hir::definitions::DefPathHash;
 use std::fmt;
 use std::hash::Hash;
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
-pub struct DepNode<K> {
-    pub kind: K,
+/// This serves as an index into arrays built by `make_dep_kind_array`.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct DepKind {
+    variant: u16,
+}
+
+impl DepKind {
+    #[inline]
+    pub const fn new(variant: u16) -> Self {
+        Self { variant }
+    }
+
+    #[inline]
+    pub const fn as_inner(&self) -> u16 {
+        self.variant
+    }
+
+    #[inline]
+    pub const fn as_usize(&self) -> usize {
+        self.variant as usize
+    }
+}
+
+static_assert_size!(DepKind, 2);
+
+pub fn default_dep_kind_debug(kind: DepKind, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    f.debug_struct("DepKind").field("variant", &kind.variant).finish()
+}
+
+pub static DEP_KIND_DEBUG: AtomicRef<fn(DepKind, &mut fmt::Formatter<'_>) -> fmt::Result> =
+    AtomicRef::new(&(default_dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
+
+impl fmt::Debug for DepKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (*DEP_KIND_DEBUG)(*self, f)
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct DepNode {
+    pub kind: DepKind,
     pub hash: PackedFingerprint,
 }
 
-impl<K: DepKind> DepNode<K> {
+// We keep a lot of `DepNode`s in memory during compilation. It's not
+// required that their size stay the same, but we don't want to change
+// it inadvertently. This assert just ensures we're aware of any change.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static_assert_size!(DepNode, 18);
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+static_assert_size!(DepNode, 24);
+
+impl DepNode {
     /// Creates a new, parameterless DepNode. This method will assert
     /// that the DepNode corresponding to the given DepKind actually
     /// does not require any parameters.
-    pub fn new_no_params<Tcx>(tcx: Tcx, kind: K) -> DepNode<K>
+    pub fn new_no_params<Tcx>(tcx: Tcx, kind: DepKind) -> DepNode
     where
-        Tcx: super::DepContext<DepKind = K>,
+        Tcx: super::DepContext,
     {
         debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
         DepNode { kind, hash: Fingerprint::ZERO.into() }
     }
 
-    pub fn construct<Tcx, Key>(tcx: Tcx, kind: K, arg: &Key) -> DepNode<K>
+    pub fn construct<Tcx, Key>(tcx: Tcx, kind: DepKind, arg: &Key) -> DepNode
     where
-        Tcx: super::DepContext<DepKind = K>,
+        Tcx: super::DepContext,
         Key: DepNodeParams<Tcx>,
     {
         let hash = arg.to_fingerprint(tcx);
@@ -93,18 +141,25 @@ impl<K: DepKind> DepNode<K> {
     /// Construct a DepNode from the given DepKind and DefPathHash. This
     /// method will assert that the given DepKind actually requires a
     /// single DefId/DefPathHash parameter.
-    pub fn from_def_path_hash<Tcx>(tcx: Tcx, def_path_hash: DefPathHash, kind: K) -> Self
+    pub fn from_def_path_hash<Tcx>(tcx: Tcx, def_path_hash: DefPathHash, kind: DepKind) -> Self
     where
-        Tcx: super::DepContext<DepKind = K>,
+        Tcx: super::DepContext,
     {
         debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
         DepNode { kind, hash: def_path_hash.0.into() }
     }
 }
 
-impl<K: DepKind> fmt::Debug for DepNode<K> {
+pub fn default_dep_node_debug(node: DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    f.debug_struct("DepNode").field("kind", &node.kind).field("hash", &node.hash).finish()
+}
+
+pub static DEP_NODE_DEBUG: AtomicRef<fn(DepNode, &mut fmt::Formatter<'_>) -> fmt::Result> =
+    AtomicRef::new(&(default_dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
+
+impl fmt::Debug for DepNode {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        K::debug_node(self, f)
+        (*DEP_NODE_DEBUG)(*self, f)
     }
 }
 
@@ -129,7 +184,7 @@ pub trait DepNodeParams<Tcx: DepContext>: fmt::Debug + Sized {
     /// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
     /// It is always valid to return `None` here, in which case incremental
     /// compilation will treat the query as having changed instead of forcing it.
-    fn recover(tcx: Tcx, dep_node: &DepNode<Tcx::DepKind>) -> Option<Self>;
+    fn recover(tcx: Tcx, dep_node: &DepNode) -> Option<Self>;
 }
 
 impl<Tcx: DepContext, T> DepNodeParams<Tcx> for T
@@ -156,7 +211,7 @@ where
     }
 
     #[inline(always)]
-    default fn recover(_: Tcx, _: &DepNode<Tcx::DepKind>) -> Option<Self> {
+    default fn recover(_: Tcx, _: &DepNode) -> Option<Self> {
         None
     }
 }
@@ -216,10 +271,13 @@ pub struct DepKindStruct<Tcx: DepContext> {
     /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
     /// is actually a `DefPathHash`, and can therefore just look up the corresponding
     /// `DefId` in `tcx.def_path_hash_to_def_id`.
-    pub force_from_dep_node: Option<fn(tcx: Tcx, dep_node: DepNode<Tcx::DepKind>) -> bool>,
+    pub force_from_dep_node: Option<fn(tcx: Tcx, dep_node: DepNode) -> bool>,
 
     /// Invoke a query to put the on-disk cached value in memory.
-    pub try_load_from_on_disk_cache: Option<fn(Tcx, DepNode<Tcx::DepKind>)>,
+    pub try_load_from_on_disk_cache: Option<fn(Tcx, DepNode)>,
+
+    /// The name of this dep kind.
+    pub name: &'static &'static str,
 }
 
 /// A "work product" corresponds to a `.o` (or other) file that we
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index fa54e1a2e6a..c7e92d7b2b2 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -17,7 +17,7 @@ use std::sync::atomic::Ordering::Relaxed;
 
 use super::query::DepGraphQuery;
 use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
-use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
+use super::{DepContext, DepKind, DepNode, Deps, HasDepContext, WorkProductId};
 use crate::dep_graph::EdgesVec;
 use crate::ich::StableHashingContext;
 use crate::query::{QueryContext, QuerySideEffects};
@@ -26,8 +26,8 @@ use crate::query::{QueryContext, QuerySideEffects};
 use {super::debug::EdgeFilter, std::env};
 
 #[derive(Clone)]
-pub struct DepGraph<K: DepKind> {
-    data: Option<Lrc<DepGraphData<K>>>,
+pub struct DepGraph<D: Deps> {
+    data: Option<Lrc<DepGraphData<D>>>,
 
     /// This field is used for assigning DepNodeIndices when running in
     /// non-incremental mode. Even in non-incremental mode we make sure that
@@ -74,16 +74,16 @@ impl DepNodeColor {
     }
 }
 
-pub struct DepGraphData<K: DepKind> {
+pub struct DepGraphData<D: Deps> {
     /// The new encoding of the dependency graph, optimized for red/green
     /// tracking. The `current` field is the dependency graph of only the
     /// current compilation session: We don't merge the previous dep-graph into
     /// current one anymore, but we do reference shared data to save space.
-    current: CurrentDepGraph<K>,
+    current: CurrentDepGraph<D>,
 
     /// The dep-graph from the previous compilation session. It contains all
     /// nodes and edges as well as all fingerprints of nodes that have them.
-    previous: SerializedDepGraph<K>,
+    previous: SerializedDepGraph,
 
     colors: DepNodeColorMap,
 
@@ -95,12 +95,12 @@ pub struct DepGraphData<K: DepKind> {
     /// this map. We can later look for and extract that data.
     previous_work_products: WorkProductMap,
 
-    dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
+    dep_node_debug: Lock<FxHashMap<DepNode, String>>,
 
     /// Used by incremental compilation tests to assert that
     /// a particular query result was decoded from disk
     /// (not just marked green)
-    debug_loaded_from_disk: Lock<FxHashSet<DepNode<K>>>,
+    debug_loaded_from_disk: Lock<FxHashSet<DepNode>>,
 }
 
 pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
@@ -112,15 +112,15 @@ where
     stable_hasher.finish()
 }
 
-impl<K: DepKind> DepGraph<K> {
+impl<D: Deps> DepGraph<D> {
     pub fn new(
         profiler: &SelfProfilerRef,
-        prev_graph: SerializedDepGraph<K>,
+        prev_graph: SerializedDepGraph,
         prev_work_products: WorkProductMap,
         encoder: FileEncoder,
         record_graph: bool,
         record_stats: bool,
-    ) -> DepGraph<K> {
+    ) -> DepGraph<D> {
         let prev_graph_node_count = prev_graph.node_count();
 
         let current = CurrentDepGraph::new(
@@ -136,7 +136,7 @@ impl<K: DepKind> DepGraph<K> {
         // Instantiate a dependy-less node only once for anonymous queries.
         let _green_node_index = current.intern_new_node(
             profiler,
-            DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() },
+            DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() },
             EdgesVec::new(),
             Fingerprint::ZERO,
         );
@@ -146,7 +146,7 @@ impl<K: DepKind> DepGraph<K> {
         let (red_node_index, red_node_prev_index_and_color) = current.intern_node(
             profiler,
             &prev_graph,
-            DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
+            DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() },
             EdgesVec::new(),
             None,
             false,
@@ -181,12 +181,12 @@ impl<K: DepKind> DepGraph<K> {
         }
     }
 
-    pub fn new_disabled() -> DepGraph<K> {
+    pub fn new_disabled() -> DepGraph<D> {
         DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
     }
 
     #[inline]
-    pub fn data(&self) -> Option<&DepGraphData<K>> {
+    pub fn data(&self) -> Option<&DepGraphData<D>> {
         self.data.as_deref()
     }
 
@@ -196,7 +196,7 @@ impl<K: DepKind> DepGraph<K> {
         self.data.is_some()
     }
 
-    pub fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) {
+    pub fn with_query(&self, f: impl Fn(&DepGraphQuery)) {
         if let Some(data) = &self.data {
             data.current.encoder.borrow().with_query(f)
         }
@@ -204,7 +204,7 @@ impl<K: DepKind> DepGraph<K> {
 
     pub fn assert_ignored(&self) {
         if let Some(..) = self.data {
-            K::read_deps(|task_deps| {
+            D::read_deps(|task_deps| {
                 assert_matches!(
                     task_deps,
                     TaskDepsRef::Ignore,
@@ -218,7 +218,7 @@ impl<K: DepKind> DepGraph<K> {
     where
         OP: FnOnce() -> R,
     {
-        K::with_deps(TaskDepsRef::Ignore, op)
+        D::with_deps(TaskDepsRef::Ignore, op)
     }
 
     /// Used to wrap the deserialization of a query result from disk,
@@ -271,13 +271,13 @@ impl<K: DepKind> DepGraph<K> {
     where
         OP: FnOnce() -> R,
     {
-        K::with_deps(TaskDepsRef::Forbid, op)
+        D::with_deps(TaskDepsRef::Forbid, op)
     }
 
     #[inline(always)]
-    pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
+    pub fn with_task<Ctxt: HasDepContext<Deps = D>, A: Debug, R>(
         &self,
-        key: DepNode<K>,
+        key: DepNode,
         cx: Ctxt,
         arg: A,
         task: fn(Ctxt, A) -> R,
@@ -289,10 +289,10 @@ impl<K: DepKind> DepGraph<K> {
         }
     }
 
-    pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>(
+    pub fn with_anon_task<Tcx: DepContext<Deps = D>, OP, R>(
         &self,
         cx: Tcx,
-        dep_kind: K,
+        dep_kind: DepKind,
         op: OP,
     ) -> (R, DepNodeIndex)
     where
@@ -305,7 +305,7 @@ impl<K: DepKind> DepGraph<K> {
     }
 }
 
-impl<K: DepKind> DepGraphData<K> {
+impl<D: Deps> DepGraphData<D> {
     /// Starts a new dep-graph task. Dep-graph tasks are specified
     /// using a free function (`task`) and **not** a closure -- this
     /// is intentional because we want to exercise tight control over
@@ -334,9 +334,9 @@ impl<K: DepKind> DepGraphData<K> {
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html
     #[inline(always)]
-    pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
+    pub fn with_task<Ctxt: HasDepContext<Deps = D>, A: Debug, R>(
         &self,
-        key: DepNode<K>,
+        key: DepNode,
         cx: Ctxt,
         arg: A,
         task: fn(Ctxt, A) -> R,
@@ -354,7 +354,7 @@ impl<K: DepKind> DepGraphData<K> {
                  - dep-node: {key:?}"
         );
 
-        let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg));
+        let with_deps = |task_deps| D::with_deps(task_deps, || task(cx, arg));
         let (result, edges) = if cx.dep_context().is_eval_always(key.kind) {
             (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new())
         } else {
@@ -402,10 +402,10 @@ impl<K: DepKind> DepGraphData<K> {
 
     /// Executes something within an "anonymous" task, that is, a task the
     /// `DepNode` of which is determined by the list of inputs it read from.
-    pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>(
+    pub fn with_anon_task<Tcx: DepContext<Deps = D>, OP, R>(
         &self,
         cx: Tcx,
-        dep_kind: K,
+        dep_kind: DepKind,
         op: OP,
     ) -> (R, DepNodeIndex)
     where
@@ -414,7 +414,7 @@ impl<K: DepKind> DepGraphData<K> {
         debug_assert!(!cx.is_eval_always(dep_kind));
 
         let task_deps = Lock::new(TaskDeps::default());
-        let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op);
+        let result = D::with_deps(TaskDepsRef::Allow(&task_deps), op);
         let task_deps = task_deps.into_inner();
         let task_deps = task_deps.reads;
 
@@ -461,11 +461,11 @@ impl<K: DepKind> DepGraphData<K> {
     }
 }
 
-impl<K: DepKind> DepGraph<K> {
+impl<D: Deps> DepGraph<D> {
     #[inline]
     pub fn read_index(&self, dep_node_index: DepNodeIndex) {
         if let Some(ref data) = self.data {
-            K::read_deps(|task_deps| {
+            D::read_deps(|task_deps| {
                 let mut task_deps = match task_deps {
                     TaskDepsRef::Allow(deps) => deps.lock(),
                     TaskDepsRef::EvalAlways => {
@@ -532,9 +532,9 @@ impl<K: DepKind> DepGraph<K> {
     /// FIXME: If the code is changed enough for this node to be marked before requiring the
     /// caller's node, we suppose that those changes will be enough to mark this node red and
     /// force a recomputation using the "normal" way.
-    pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>(
+    pub fn with_feed_task<Ctxt: DepContext<Deps = D>, A: Debug, R: Debug>(
         &self,
-        node: DepNode<K>,
+        node: DepNode,
         cx: Ctxt,
         key: A,
         result: &R,
@@ -573,7 +573,7 @@ impl<K: DepKind> DepGraph<K> {
             }
 
             let mut edges = EdgesVec::new();
-            K::read_deps(|task_deps| match task_deps {
+            D::read_deps(|task_deps| match task_deps {
                 TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()),
                 TaskDepsRef::EvalAlways => {
                     edges.push(DepNodeIndex::FOREVER_RED_NODE);
@@ -623,9 +623,9 @@ impl<K: DepKind> DepGraph<K> {
     }
 }
 
-impl<K: DepKind> DepGraphData<K> {
+impl<D: Deps> DepGraphData<D> {
     #[inline]
-    pub fn dep_node_index_of_opt(&self, dep_node: &DepNode<K>) -> Option<DepNodeIndex> {
+    pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option<DepNodeIndex> {
         if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
             self.current.prev_index_to_index.lock()[prev_index]
         } else {
@@ -634,11 +634,11 @@ impl<K: DepKind> DepGraphData<K> {
     }
 
     #[inline]
-    pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
+    pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
         self.dep_node_index_of_opt(dep_node).is_some()
     }
 
-    fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
+    fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
         if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
             self.colors.get(prev_index)
         } else {
@@ -660,18 +660,18 @@ impl<K: DepKind> DepGraphData<K> {
     }
 
     #[inline]
-    pub fn prev_node_of(&self, prev_index: SerializedDepNodeIndex) -> DepNode<K> {
+    pub fn prev_node_of(&self, prev_index: SerializedDepNodeIndex) -> DepNode {
         self.previous.index_to_node(prev_index)
     }
 
-    pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode<K>) {
+    pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode) {
         self.debug_loaded_from_disk.lock().insert(dep_node);
     }
 }
 
-impl<K: DepKind> DepGraph<K> {
+impl<D: Deps> DepGraph<D> {
     #[inline]
-    pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
+    pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
         self.data.as_ref().is_some_and(|data| data.dep_node_exists(dep_node))
     }
 
@@ -687,12 +687,12 @@ impl<K: DepKind> DepGraph<K> {
         &self.data.as_ref().unwrap().previous_work_products
     }
 
-    pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode<K>) -> bool {
+    pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode) -> bool {
         self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node)
     }
 
     #[inline(always)]
-    pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F)
+    pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F)
     where
         F: FnOnce() -> String,
     {
@@ -705,11 +705,11 @@ impl<K: DepKind> DepGraph<K> {
         dep_node_debug.borrow_mut().insert(dep_node, debug_str);
     }
 
-    pub fn dep_node_debug_str(&self, dep_node: DepNode<K>) -> Option<String> {
+    pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> {
         self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned()
     }
 
-    fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
+    fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
         if let Some(ref data) = self.data {
             return data.node_color(dep_node);
         }
@@ -717,25 +717,25 @@ impl<K: DepKind> DepGraph<K> {
         None
     }
 
-    pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>(
+    pub fn try_mark_green<Qcx: QueryContext<Deps = D>>(
         &self,
         qcx: Qcx,
-        dep_node: &DepNode<K>,
+        dep_node: &DepNode,
     ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
         self.data().and_then(|data| data.try_mark_green(qcx, dep_node))
     }
 }
 
-impl<K: DepKind> DepGraphData<K> {
+impl<D: Deps> DepGraphData<D> {
     /// Try to mark a node index for the node dep_node.
     ///
     /// A node will have an index, when it's already been marked green, or when we can mark it
     /// green. This function will mark the current task as a reader of the specified node, when
     /// a node index can be found for that node.
-    pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>(
+    pub fn try_mark_green<Qcx: QueryContext<Deps = D>>(
         &self,
         qcx: Qcx,
-        dep_node: &DepNode<K>,
+        dep_node: &DepNode,
     ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
         debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
 
@@ -757,11 +757,11 @@ impl<K: DepKind> DepGraphData<K> {
     }
 
     #[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")]
-    fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>(
+    fn try_mark_parent_green<Qcx: QueryContext<Deps = D>>(
         &self,
         qcx: Qcx,
         parent_dep_node_index: SerializedDepNodeIndex,
-        dep_node: &DepNode<K>,
+        dep_node: &DepNode,
         frame: Option<&MarkFrame<'_>>,
     ) -> Option<()> {
         let dep_dep_node_color = self.colors.get(parent_dep_node_index);
@@ -845,11 +845,11 @@ impl<K: DepKind> DepGraphData<K> {
 
     /// Try to mark a dep-node which existed in the previous compilation session as green.
     #[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")]
-    fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
+    fn try_mark_previous_green<Qcx: QueryContext<Deps = D>>(
         &self,
         qcx: Qcx,
         prev_dep_node_index: SerializedDepNodeIndex,
-        dep_node: &DepNode<K>,
+        dep_node: &DepNode,
         frame: Option<&MarkFrame<'_>>,
     ) -> Option<DepNodeIndex> {
         let frame = MarkFrame { index: prev_dep_node_index, parent: frame };
@@ -916,7 +916,7 @@ impl<K: DepKind> DepGraphData<K> {
     /// This may be called concurrently on multiple threads for the same dep node.
     #[cold]
     #[inline(never)]
-    fn emit_side_effects<Qcx: QueryContext<DepKind = K>>(
+    fn emit_side_effects<Qcx: QueryContext<Deps = D>>(
         &self,
         qcx: Qcx,
         dep_node_index: DepNodeIndex,
@@ -940,16 +940,16 @@ impl<K: DepKind> DepGraphData<K> {
     }
 }
 
-impl<K: DepKind> DepGraph<K> {
+impl<D: Deps> DepGraph<D> {
     /// Returns true if the given node has been marked as red during the
     /// current compilation session. Used in various assertions
-    pub fn is_red(&self, dep_node: &DepNode<K>) -> bool {
+    pub fn is_red(&self, dep_node: &DepNode) -> bool {
         self.node_color(dep_node) == Some(DepNodeColor::Red)
     }
 
     /// Returns true if the given node has been marked as green during the
     /// current compilation session. Used in various assertions
-    pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
+    pub fn is_green(&self, dep_node: &DepNode) -> bool {
         self.node_color(dep_node).is_some_and(|c| c.is_green())
     }
 
@@ -961,7 +961,7 @@ impl<K: DepKind> DepGraph<K> {
     ///
     /// This method will only load queries that will end up in the disk cache.
     /// Other queries will not be executed.
-    pub fn exec_cache_promotions<Tcx: DepContext<DepKind = K>>(&self, tcx: Tcx) {
+    pub fn exec_cache_promotions<Tcx: DepContext>(&self, tcx: Tcx) {
         let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
 
         let data = self.data.as_ref().unwrap();
@@ -1076,9 +1076,9 @@ rustc_index::newtype_index! {
 /// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When
 /// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index`
 /// first, and `data` second.
-pub(super) struct CurrentDepGraph<K: DepKind> {
-    encoder: Steal<GraphEncoder<K>>,
-    new_node_to_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>,
+pub(super) struct CurrentDepGraph<D: Deps> {
+    encoder: Steal<GraphEncoder<D>>,
+    new_node_to_index: Sharded<FxHashMap<DepNode, DepNodeIndex>>,
     prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>,
 
     /// This is used to verify that fingerprints do not change between the creation of a node
@@ -1089,7 +1089,7 @@ pub(super) struct CurrentDepGraph<K: DepKind> {
     /// Used to trap when a specific edge is added to the graph.
     /// This is used for debug purposes and is only active with `debug_assertions`.
     #[cfg(debug_assertions)]
-    forbidden_edge: Option<EdgeFilter<K>>,
+    forbidden_edge: Option<EdgeFilter>,
 
     /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
     /// their edges. This has the beneficial side-effect that multiple anonymous
@@ -1116,14 +1116,14 @@ pub(super) struct CurrentDepGraph<K: DepKind> {
     node_intern_event_id: Option<EventId>,
 }
 
-impl<K: DepKind> CurrentDepGraph<K> {
+impl<D: Deps> CurrentDepGraph<D> {
     fn new(
         profiler: &SelfProfilerRef,
         prev_graph_node_count: usize,
         encoder: FileEncoder,
         record_graph: bool,
         record_stats: bool,
-    ) -> CurrentDepGraph<K> {
+    ) -> Self {
         use std::time::{SystemTime, UNIX_EPOCH};
 
         let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
@@ -1178,7 +1178,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     }
 
     #[cfg(debug_assertions)]
-    fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode<K>, fingerprint: Fingerprint) {
+    fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) {
         if let Some(forbidden_edge) = &self.forbidden_edge {
             forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
         }
@@ -1192,7 +1192,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     fn intern_new_node(
         &self,
         profiler: &SelfProfilerRef,
-        key: DepNode<K>,
+        key: DepNode,
         edges: EdgesVec,
         current_fingerprint: Fingerprint,
     ) -> DepNodeIndex {
@@ -1215,8 +1215,8 @@ impl<K: DepKind> CurrentDepGraph<K> {
     fn intern_node(
         &self,
         profiler: &SelfProfilerRef,
-        prev_graph: &SerializedDepGraph<K>,
-        key: DepNode<K>,
+        prev_graph: &SerializedDepGraph,
+        key: DepNode,
         edges: EdgesVec,
         fingerprint: Option<Fingerprint>,
         print_status: bool,
@@ -1289,7 +1289,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     fn promote_node_and_deps_to_current(
         &self,
         profiler: &SelfProfilerRef,
-        prev_graph: &SerializedDepGraph<K>,
+        prev_graph: &SerializedDepGraph,
         prev_index: SerializedDepNodeIndex,
     ) -> DepNodeIndex {
         self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
@@ -1317,7 +1317,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     #[inline]
     fn debug_assert_not_in_new_nodes(
         &self,
-        prev_graph: &SerializedDepGraph<K>,
+        prev_graph: &SerializedDepGraph,
         prev_index: SerializedDepNodeIndex,
     ) {
         let node = &prev_graph.index_to_node(prev_index);
@@ -1329,11 +1329,11 @@ impl<K: DepKind> CurrentDepGraph<K> {
 }
 
 #[derive(Debug, Clone, Copy)]
-pub enum TaskDepsRef<'a, K: DepKind> {
+pub enum TaskDepsRef<'a> {
     /// New dependencies can be added to the
     /// `TaskDeps`. This is used when executing a 'normal' query
     /// (no `eval_always` modifier)
-    Allow(&'a Lock<TaskDeps<K>>),
+    Allow(&'a Lock<TaskDeps>),
     /// This is used when executing an `eval_always` query. We don't
     /// need to track dependencies for a query that's always
     /// re-executed -- but we need to know that this is an `eval_always`
@@ -1350,15 +1350,15 @@ pub enum TaskDepsRef<'a, K: DepKind> {
 }
 
 #[derive(Debug)]
-pub struct TaskDeps<K: DepKind> {
+pub struct TaskDeps {
     #[cfg(debug_assertions)]
-    node: Option<DepNode<K>>,
+    node: Option<DepNode>,
     reads: EdgesVec,
     read_set: FxHashSet<DepNodeIndex>,
-    phantom_data: PhantomData<DepNode<K>>,
+    phantom_data: PhantomData<DepNode>,
 }
 
-impl<K: DepKind> Default for TaskDeps<K> {
+impl Default for TaskDeps {
     fn default() -> Self {
         Self {
             #[cfg(debug_assertions)]
@@ -1410,10 +1410,7 @@ impl DepNodeColorMap {
 
 #[inline(never)]
 #[cold]
-pub(crate) fn print_markframe_trace<K: DepKind>(
-    graph: &DepGraph<K>,
-    frame: Option<&MarkFrame<'_>>,
-) {
+pub(crate) fn print_markframe_trace<D: Deps>(graph: &DepGraph<D>, frame: Option<&MarkFrame<'_>>) {
     let data = graph.data.as_ref().unwrap();
 
     eprintln!("there was a panic while trying to force a dep node");
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 272028d35bf..624ae680a8f 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -1,11 +1,11 @@
 pub mod debug;
-mod dep_node;
+pub mod dep_node;
 mod edges;
 mod graph;
 mod query;
 mod serialized;
 
-pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId};
+pub use dep_node::{DepKind, DepKindStruct, DepNode, DepNodeParams, WorkProductId};
 pub use edges::EdgesVec;
 pub use graph::{
     hash_result, DepGraph, DepGraphData, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef,
@@ -16,22 +16,20 @@ pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 
 use crate::ich::StableHashingContext;
 use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_serialize::{opaque::FileEncoder, Encodable};
 use rustc_session::Session;
 
-use std::hash::Hash;
-use std::{fmt, panic};
+use std::panic;
 
 use self::graph::{print_markframe_trace, MarkFrame};
 
 pub trait DepContext: Copy {
-    type DepKind: self::DepKind;
+    type Deps: Deps;
 
     /// Create a hashing context for hashing new results.
     fn with_stable_hashing_context<R>(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R;
 
     /// Access the DepGraph.
-    fn dep_graph(&self) -> &DepGraph<Self::DepKind>;
+    fn dep_graph(&self) -> &DepGraph<Self::Deps>;
 
     /// Access the profiler.
     fn profiler(&self) -> &SelfProfilerRef;
@@ -39,10 +37,10 @@ pub trait DepContext: Copy {
     /// Access the compiler session.
     fn sess(&self) -> &Session;
 
-    fn dep_kind_info(&self, dep_node: Self::DepKind) -> &DepKindStruct<Self>;
+    fn dep_kind_info(&self, dep_node: DepKind) -> &DepKindStruct<Self>;
 
     #[inline(always)]
-    fn fingerprint_style(self, kind: Self::DepKind) -> FingerprintStyle {
+    fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle {
         let data = self.dep_kind_info(kind);
         if data.is_anon {
             return FingerprintStyle::Opaque;
@@ -52,18 +50,14 @@ pub trait DepContext: Copy {
 
     #[inline(always)]
     /// Return whether this kind always require evaluation.
-    fn is_eval_always(self, kind: Self::DepKind) -> bool {
+    fn is_eval_always(self, kind: DepKind) -> bool {
         self.dep_kind_info(kind).is_eval_always
     }
 
     /// Try to force a dep node to execute and see if it's green.
     #[inline]
     #[instrument(skip(self, frame), level = "debug")]
-    fn try_force_from_dep_node(
-        self,
-        dep_node: DepNode<Self::DepKind>,
-        frame: Option<&MarkFrame<'_>>,
-    ) -> bool {
+    fn try_force_from_dep_node(self, dep_node: DepNode, frame: Option<&MarkFrame<'_>>) -> bool {
         let cb = self.dep_kind_info(dep_node.kind);
         if let Some(f) = cb.force_from_dep_node {
             if let Err(value) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
@@ -81,7 +75,7 @@ pub trait DepContext: Copy {
     }
 
     /// Load data from the on-disk cache.
-    fn try_load_from_on_disk_cache(self, dep_node: DepNode<Self::DepKind>) {
+    fn try_load_from_on_disk_cache(self, dep_node: DepNode) {
         let cb = self.dep_kind_info(dep_node.kind);
         if let Some(f) = cb.try_load_from_on_disk_cache {
             f(self, dep_node)
@@ -89,15 +83,37 @@ pub trait DepContext: Copy {
     }
 }
 
+pub trait Deps {
+    /// Execute the operation with provided dependencies.
+    fn with_deps<OP, R>(deps: TaskDepsRef<'_>, op: OP) -> R
+    where
+        OP: FnOnce() -> R;
+
+    /// Access dependencies from current implicit context.
+    fn read_deps<OP>(op: OP)
+    where
+        OP: for<'a> FnOnce(TaskDepsRef<'a>);
+
+    /// We use this for most things when incr. comp. is turned off.
+    const DEP_KIND_NULL: DepKind;
+
+    /// We use this to create a forever-red node.
+    const DEP_KIND_RED: DepKind;
+
+    /// This is the highest value a `DepKind` can have. It's used during encoding to
+    /// pack information into the unused bits.
+    const DEP_KIND_MAX: u16;
+}
+
 pub trait HasDepContext: Copy {
-    type DepKind: self::DepKind;
-    type DepContext: self::DepContext<DepKind = Self::DepKind>;
+    type Deps: self::Deps;
+    type DepContext: self::DepContext<Deps = Self::Deps>;
 
     fn dep_context(&self) -> &Self::DepContext;
 }
 
 impl<T: DepContext> HasDepContext for T {
-    type DepKind = T::DepKind;
+    type Deps = T::Deps;
     type DepContext = Self;
 
     fn dep_context(&self) -> &Self::DepContext {
@@ -106,7 +122,7 @@ impl<T: DepContext> HasDepContext for T {
 }
 
 impl<T: HasDepContext, Q: Copy> HasDepContext for (T, Q) {
-    type DepKind = T::DepKind;
+    type Deps = T::Deps;
     type DepContext = T::DepContext;
 
     fn dep_context(&self) -> &Self::DepContext {
@@ -138,31 +154,3 @@ impl FingerprintStyle {
         }
     }
 }
-
-/// Describe the different families of dependency nodes.
-pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static {
-    /// DepKind to use when incr. comp. is turned off.
-    const NULL: Self;
-
-    /// DepKind to use to create the initial forever-red node.
-    const RED: Self;
-
-    /// Implementation of `std::fmt::Debug` for `DepNode`.
-    fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
-
-    /// Execute the operation with provided dependencies.
-    fn with_deps<OP, R>(deps: TaskDepsRef<'_, Self>, op: OP) -> R
-    where
-        OP: FnOnce() -> R;
-
-    /// Access dependencies from current implicit context.
-    fn read_deps<OP>(op: OP)
-    where
-        OP: for<'a> FnOnce(TaskDepsRef<'a, Self>);
-
-    fn from_u16(u: u16) -> Self;
-
-    fn to_u16(self) -> u16;
-
-    const MAX: u16;
-}
diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs
index 5cbc6bf8f8a..5969e5fbe98 100644
--- a/compiler/rustc_query_system/src/dep_graph/query.rs
+++ b/compiler/rustc_query_system/src/dep_graph/query.rs
@@ -2,16 +2,16 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING};
 use rustc_index::IndexVec;
 
-use super::{DepKind, DepNode, DepNodeIndex};
+use super::{DepNode, DepNodeIndex};
 
-pub struct DepGraphQuery<K> {
-    pub graph: Graph<DepNode<K>, ()>,
-    pub indices: FxHashMap<DepNode<K>, NodeIndex>,
+pub struct DepGraphQuery {
+    pub graph: Graph<DepNode, ()>,
+    pub indices: FxHashMap<DepNode, NodeIndex>,
     pub dep_index_to_index: IndexVec<DepNodeIndex, Option<NodeIndex>>,
 }
 
-impl<K: DepKind> DepGraphQuery<K> {
-    pub fn new(prev_node_count: usize) -> DepGraphQuery<K> {
+impl DepGraphQuery {
+    pub fn new(prev_node_count: usize) -> DepGraphQuery {
         let node_count = prev_node_count + prev_node_count / 4;
         let edge_count = 6 * node_count;
 
@@ -22,7 +22,7 @@ impl<K: DepKind> DepGraphQuery<K> {
         DepGraphQuery { graph, indices, dep_index_to_index }
     }
 
-    pub fn push(&mut self, index: DepNodeIndex, node: DepNode<K>, edges: &[DepNodeIndex]) {
+    pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) {
         let source = self.graph.add_node(node);
         self.dep_index_to_index.insert(index, source);
         self.indices.insert(node, source);
@@ -37,11 +37,11 @@ impl<K: DepKind> DepGraphQuery<K> {
         }
     }
 
-    pub fn nodes(&self) -> Vec<&DepNode<K>> {
+    pub fn nodes(&self) -> Vec<&DepNode> {
         self.graph.all_nodes().iter().map(|n| &n.data).collect()
     }
 
-    pub fn edges(&self) -> Vec<(&DepNode<K>, &DepNode<K>)> {
+    pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> {
         self.graph
             .all_edges()
             .iter()
@@ -50,7 +50,7 @@ impl<K: DepKind> DepGraphQuery<K> {
             .collect()
     }
 
-    fn reachable_nodes(&self, node: &DepNode<K>, direction: Direction) -> Vec<&DepNode<K>> {
+    fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> {
         if let Some(&index) = self.indices.get(node) {
             self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect()
         } else {
@@ -59,7 +59,7 @@ impl<K: DepKind> DepGraphQuery<K> {
     }
 
     /// All nodes that can reach `node`.
-    pub fn transitive_predecessors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
+    pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> {
         self.reachable_nodes(node, INCOMING)
     }
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 07eb10cba02..fcf46be6e6f 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -36,7 +36,7 @@
 //! store it directly after the header with leb128.
 
 use super::query::DepGraphQuery;
-use super::{DepKind, DepNode, DepNodeIndex};
+use super::{DepKind, DepNode, DepNodeIndex, Deps};
 use crate::dep_graph::EdgesVec;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fingerprint::PackedFingerprint;
@@ -70,9 +70,9 @@ const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
 
 /// Data for use when recompiling the **current crate**.
 #[derive(Debug)]
-pub struct SerializedDepGraph<K: DepKind> {
+pub struct SerializedDepGraph {
     /// The set of all DepNodes in the graph
-    nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
+    nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
     /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
     /// the DepNode at the same index in the nodes vector.
     fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
@@ -88,7 +88,7 @@ pub struct SerializedDepGraph<K: DepKind> {
     index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
 }
 
-impl<K: DepKind> Default for SerializedDepGraph<K> {
+impl Default for SerializedDepGraph {
     fn default() -> Self {
         SerializedDepGraph {
             nodes: Default::default(),
@@ -100,7 +100,7 @@ impl<K: DepKind> Default for SerializedDepGraph<K> {
     }
 }
 
-impl<K: DepKind> SerializedDepGraph<K> {
+impl SerializedDepGraph {
     #[inline]
     pub fn edge_targets_from(
         &self,
@@ -134,13 +134,13 @@ impl<K: DepKind> SerializedDepGraph<K> {
     }
 
     #[inline]
-    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
+    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode {
         self.nodes[dep_node_index]
     }
 
     #[inline]
-    pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
-        self.index.get(dep_node.kind.to_u16() as usize)?.get(&dep_node.hash).cloned()
+    pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
+        self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned()
     }
 
     #[inline]
@@ -184,11 +184,9 @@ fn mask(bits: usize) -> usize {
     usize::MAX >> ((std::mem::size_of::<usize>() * 8) - bits)
 }
 
-impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
-    for SerializedDepGraph<K>
-{
+impl SerializedDepGraph {
     #[instrument(level = "debug", skip(d))]
-    fn decode(d: &mut MemDecoder<'a>) -> SerializedDepGraph<K> {
+    pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> SerializedDepGraph {
         // The last 16 bytes are the node count and edge count.
         debug!("position: {:?}", d.position());
         let (node_count, edge_count) =
@@ -217,14 +215,14 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
         // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128
         // length is about the same fractional overhead and it amortizes for yet greater lengths.
         let mut edge_list_data = Vec::with_capacity(
-            graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<K>>(),
+            graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<D>>(),
         );
 
         for _index in 0..node_count {
             // Decode the header for this edge; the header packs together as many of the fixed-size
             // fields as possible to limit the number of times we update decoder state.
             let node_header =
-                SerializedNodeHeader::<K> { bytes: d.read_array(), _marker: PhantomData };
+                SerializedNodeHeader::<D> { bytes: d.read_array(), _marker: PhantomData };
 
             let _i: SerializedDepNodeIndex = nodes.push(node_header.node());
             debug_assert_eq!(_i.index(), _index);
@@ -256,12 +254,12 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
         edge_list_data.extend(&[0u8; DEP_NODE_PAD]);
 
         // Read the number of each dep kind and use it to create an hash map with a suitable size.
-        let mut index: Vec<_> = (0..(K::MAX as usize + 1))
+        let mut index: Vec<_> = (0..(D::DEP_KIND_MAX + 1))
             .map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default()))
             .collect();
 
         for (idx, node) in nodes.iter_enumerated() {
-            index[node.kind.to_u16() as usize].insert(node.hash, idx);
+            index[node.kind.as_usize()].insert(node.hash, idx);
         }
 
         SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
@@ -276,20 +274,20 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
 /// * The `DepKind`'s discriminant (a u16, but not all bits are used...)
 /// * The byte width of the encoded edges for this node
 /// * In whatever bits remain, the length of the edge list for this node, if it fits
-struct SerializedNodeHeader<K> {
+struct SerializedNodeHeader<D> {
     // 2 bytes for the DepNode
     // 16 for Fingerprint in DepNode
     // 16 for Fingerprint in NodeInfo
     bytes: [u8; 34],
-    _marker: PhantomData<K>,
+    _marker: PhantomData<D>,
 }
 
 // The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only
 // to make the implementation of `SerializedNodeHeader` simpler.
-struct Unpacked<K> {
+struct Unpacked {
     len: Option<usize>,
     bytes_per_index: usize,
-    kind: K,
+    kind: DepKind,
     hash: PackedFingerprint,
     fingerprint: Fingerprint,
 }
@@ -301,20 +299,20 @@ struct Unpacked<K> {
 // 0..M    length of the edge
 // M..M+N  bytes per index
 // M+N..16 kind
-impl<K: DepKind> SerializedNodeHeader<K> {
-    const TOTAL_BITS: usize = std::mem::size_of::<K>() * 8;
+impl<D: Deps> SerializedNodeHeader<D> {
+    const TOTAL_BITS: usize = std::mem::size_of::<DepKind>() * 8;
     const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS;
     const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS;
-    const KIND_BITS: usize = Self::TOTAL_BITS - K::MAX.leading_zeros() as usize;
+    const KIND_BITS: usize = Self::TOTAL_BITS - D::DEP_KIND_MAX.leading_zeros() as usize;
     const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1;
 
     #[inline]
-    fn new(node_info: &NodeInfo<K>) -> Self {
+    fn new(node_info: &NodeInfo) -> Self {
         debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS);
 
         let NodeInfo { node, fingerprint, edges } = node_info;
 
-        let mut head = node.kind.to_u16();
+        let mut head = node.kind.as_inner();
 
         let free_bytes = edges.max_index().leading_zeros() as usize / 8;
         let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1);
@@ -347,7 +345,7 @@ impl<K: DepKind> SerializedNodeHeader<K> {
     }
 
     #[inline]
-    fn unpack(&self) -> Unpacked<K> {
+    fn unpack(&self) -> Unpacked {
         let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap());
         let hash = self.bytes[2..18].try_into().unwrap();
         let fingerprint = self.bytes[18..].try_into().unwrap();
@@ -359,7 +357,7 @@ impl<K: DepKind> SerializedNodeHeader<K> {
         Unpacked {
             len: len.checked_sub(1),
             bytes_per_index: bytes_per_index as usize + 1,
-            kind: DepKind::from_u16(kind),
+            kind: DepKind::new(kind),
             hash: Fingerprint::from_le_bytes(hash).into(),
             fingerprint: Fingerprint::from_le_bytes(fingerprint),
         }
@@ -381,7 +379,7 @@ impl<K: DepKind> SerializedNodeHeader<K> {
     }
 
     #[inline]
-    fn node(&self) -> DepNode<K> {
+    fn node(&self) -> DepNode {
         let Unpacked { kind, hash, .. } = self.unpack();
         DepNode { kind, hash }
     }
@@ -395,15 +393,15 @@ impl<K: DepKind> SerializedNodeHeader<K> {
 }
 
 #[derive(Debug)]
-struct NodeInfo<K: DepKind> {
-    node: DepNode<K>,
+struct NodeInfo {
+    node: DepNode,
     fingerprint: Fingerprint,
     edges: EdgesVec,
 }
 
-impl<K: DepKind> Encodable<FileEncoder> for NodeInfo<K> {
-    fn encode(&self, e: &mut FileEncoder) {
-        let header = SerializedNodeHeader::new(self);
+impl NodeInfo {
+    fn encode<D: Deps>(&self, e: &mut FileEncoder) {
+        let header = SerializedNodeHeader::<D>::new(self);
         e.write_array(header.bytes);
 
         if header.len().is_none() {
@@ -420,41 +418,43 @@ impl<K: DepKind> Encodable<FileEncoder> for NodeInfo<K> {
     }
 }
 
-struct Stat<K: DepKind> {
-    kind: K,
+struct Stat {
+    kind: DepKind,
     node_counter: u64,
     edge_counter: u64,
 }
 
-struct EncoderState<K: DepKind> {
+struct EncoderState<D: Deps> {
     encoder: FileEncoder,
     total_node_count: usize,
     total_edge_count: usize,
-    stats: Option<FxHashMap<K, Stat<K>>>,
+    stats: Option<FxHashMap<DepKind, Stat>>,
 
     /// Stores the number of times we've encoded each dep kind.
     kind_stats: Vec<u32>,
+    marker: PhantomData<D>,
 }
 
-impl<K: DepKind> EncoderState<K> {
+impl<D: Deps> EncoderState<D> {
     fn new(encoder: FileEncoder, record_stats: bool) -> Self {
         Self {
             encoder,
             total_edge_count: 0,
             total_node_count: 0,
             stats: record_stats.then(FxHashMap::default),
-            kind_stats: iter::repeat(0).take(K::MAX as usize + 1).collect(),
+            kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(),
+            marker: PhantomData,
         }
     }
 
     fn encode_node(
         &mut self,
-        node: &NodeInfo<K>,
-        record_graph: &Option<Lock<DepGraphQuery<K>>>,
+        node: &NodeInfo,
+        record_graph: &Option<Lock<DepGraphQuery>>,
     ) -> DepNodeIndex {
         let index = DepNodeIndex::new(self.total_node_count);
         self.total_node_count += 1;
-        self.kind_stats[node.node.kind.to_u16() as usize] += 1;
+        self.kind_stats[node.node.kind.as_usize()] += 1;
 
         let edge_count = node.edges.len();
         self.total_edge_count += edge_count;
@@ -475,12 +475,19 @@ impl<K: DepKind> EncoderState<K> {
         }
 
         let encoder = &mut self.encoder;
-        node.encode(encoder);
+        node.encode::<D>(encoder);
         index
     }
 
     fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
-        let Self { mut encoder, total_node_count, total_edge_count, stats: _, kind_stats } = self;
+        let Self {
+            mut encoder,
+            total_node_count,
+            total_edge_count,
+            stats: _,
+            kind_stats,
+            marker: _,
+        } = self;
 
         let node_count = total_node_count.try_into().unwrap();
         let edge_count = total_edge_count.try_into().unwrap();
@@ -506,12 +513,12 @@ impl<K: DepKind> EncoderState<K> {
     }
 }
 
-pub struct GraphEncoder<K: DepKind> {
-    status: Lock<EncoderState<K>>,
-    record_graph: Option<Lock<DepGraphQuery<K>>>,
+pub struct GraphEncoder<D: Deps> {
+    status: Lock<EncoderState<D>>,
+    record_graph: Option<Lock<DepGraphQuery>>,
 }
 
-impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> {
+impl<D: Deps> GraphEncoder<D> {
     pub fn new(
         encoder: FileEncoder,
         prev_node_count: usize,
@@ -523,7 +530,7 @@ impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> {
         GraphEncoder { status, record_graph }
     }
 
-    pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) {
+    pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) {
         if let Some(record_graph) = &self.record_graph {
             f(&record_graph.lock())
         }
@@ -584,7 +591,7 @@ impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> {
     pub(crate) fn send(
         &self,
         profiler: &SelfProfilerRef,
-        node: DepNode<K>,
+        node: DepNode,
         fingerprint: Fingerprint,
         edges: EdgesVec,
     ) -> DepNodeIndex {
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index d14c6315dc1..c025fac2631 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -1,6 +1,6 @@
 //! Query configuration and description traits.
 
-use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex};
+use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex};
 use crate::error::HandleCycleError;
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
@@ -27,7 +27,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
     fn format_value(self) -> fn(&Self::Value) -> String;
 
     // Don't use this method to access query results, instead use the methods on TyCtxt
-    fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key, Qcx::DepKind>
+    fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key>
     where
         Qcx: 'a;
 
@@ -57,7 +57,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
     fn value_from_cycle_error(
         self,
         tcx: Qcx::DepContext,
-        cycle: &[QueryInfo<Qcx::DepKind>],
+        cycle: &[QueryInfo],
         guar: ErrorGuaranteed,
     ) -> Self::Value;
 
@@ -66,12 +66,12 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
     fn depth_limit(self) -> bool;
     fn feedable(self) -> bool;
 
-    fn dep_kind(self) -> Qcx::DepKind;
+    fn dep_kind(self) -> DepKind;
     fn handle_cycle_error(self) -> HandleCycleError;
     fn hash_result(self) -> HashResult<Self::Value>;
 
     // Just here for convenience and checking that the key matches the kind, don't override this.
-    fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> {
+    fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode {
         DepNode::construct(tcx, self.dep_kind(), key)
     }
 }
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 6c01dc3c00d..2e9ebde296c 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -1,9 +1,8 @@
-use crate::dep_graph::DepKind;
+use crate::dep_graph::DepContext;
 use crate::error::CycleStack;
 use crate::query::plumbing::CycleError;
+use crate::query::DepKind;
 use crate::query::{QueryContext, QueryStackFrame};
-use core::marker::PhantomData;
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{
     Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, Level,
@@ -30,48 +29,48 @@ use {
 
 /// Represents a span and a query key.
 #[derive(Clone, Debug)]
-pub struct QueryInfo<D: DepKind> {
+pub struct QueryInfo {
     /// The span corresponding to the reason for which this query was required.
     pub span: Span,
-    pub query: QueryStackFrame<D>,
+    pub query: QueryStackFrame,
 }
 
-pub type QueryMap<D> = FxHashMap<QueryJobId, QueryJobInfo<D>>;
+pub type QueryMap = FxHashMap<QueryJobId, QueryJobInfo>;
 
 /// A value uniquely identifying an active query job.
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
 pub struct QueryJobId(pub NonZeroU64);
 
 impl QueryJobId {
-    fn query<D: DepKind>(self, map: &QueryMap<D>) -> QueryStackFrame<D> {
+    fn query(self, map: &QueryMap) -> QueryStackFrame {
         map.get(&self).unwrap().query.clone()
     }
 
     #[cfg(parallel_compiler)]
-    fn span<D: DepKind>(self, map: &QueryMap<D>) -> Span {
+    fn span(self, map: &QueryMap) -> Span {
         map.get(&self).unwrap().job.span
     }
 
     #[cfg(parallel_compiler)]
-    fn parent<D: DepKind>(self, map: &QueryMap<D>) -> Option<QueryJobId> {
+    fn parent(self, map: &QueryMap) -> Option<QueryJobId> {
         map.get(&self).unwrap().job.parent
     }
 
     #[cfg(parallel_compiler)]
-    fn latch<D: DepKind>(self, map: &QueryMap<D>) -> Option<&QueryLatch<D>> {
+    fn latch(self, map: &QueryMap) -> Option<&QueryLatch> {
         map.get(&self).unwrap().job.latch.as_ref()
     }
 }
 
 #[derive(Clone)]
-pub struct QueryJobInfo<D: DepKind> {
-    pub query: QueryStackFrame<D>,
-    pub job: QueryJob<D>,
+pub struct QueryJobInfo {
+    pub query: QueryStackFrame,
+    pub job: QueryJob,
 }
 
 /// Represents an active query job.
 #[derive(Clone)]
-pub struct QueryJob<D: DepKind> {
+pub struct QueryJob {
     pub id: QueryJobId,
 
     /// The span corresponding to the reason for which this query was required.
@@ -82,11 +81,10 @@ pub struct QueryJob<D: DepKind> {
 
     /// The latch that is used to wait on this job.
     #[cfg(parallel_compiler)]
-    latch: Option<QueryLatch<D>>,
-    spooky: core::marker::PhantomData<D>,
+    latch: Option<QueryLatch>,
 }
 
-impl<D: DepKind> QueryJob<D> {
+impl QueryJob {
     /// Creates a new query job.
     #[inline]
     pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
@@ -96,12 +94,11 @@ impl<D: DepKind> QueryJob<D> {
             parent,
             #[cfg(parallel_compiler)]
             latch: None,
-            spooky: PhantomData,
         }
     }
 
     #[cfg(parallel_compiler)]
-    pub(super) fn latch(&mut self) -> QueryLatch<D> {
+    pub(super) fn latch(&mut self) -> QueryLatch {
         if self.latch.is_none() {
             self.latch = Some(QueryLatch::new());
         }
@@ -124,12 +121,12 @@ impl<D: DepKind> QueryJob<D> {
 }
 
 impl QueryJobId {
-    pub(super) fn find_cycle_in_stack<D: DepKind>(
+    pub(super) fn find_cycle_in_stack(
         &self,
-        query_map: QueryMap<D>,
+        query_map: QueryMap,
         current_job: &Option<QueryJobId>,
         span: Span,
-    ) -> CycleError<D> {
+    ) -> CycleError {
         // Find the waitee amongst `current_job` parents
         let mut cycle = Vec::new();
         let mut current_job = Option::clone(current_job);
@@ -163,18 +160,18 @@ impl QueryJobId {
 
     #[cold]
     #[inline(never)]
-    pub fn try_find_layout_root<D: DepKind>(
+    pub fn try_find_layout_root(
         &self,
-        query_map: QueryMap<D>,
-    ) -> Option<(QueryJobInfo<D>, usize)> {
+        query_map: QueryMap,
+        layout_of_kind: DepKind,
+    ) -> Option<(QueryJobInfo, usize)> {
         let mut last_layout = None;
         let mut current_id = Some(*self);
         let mut depth = 0;
 
         while let Some(id) = current_id {
             let info = query_map.get(&id).unwrap();
-            // FIXME: This string comparison should probably not be done.
-            if format!("{:?}", info.query.dep_kind) == "layout_of" {
+            if info.query.dep_kind == layout_of_kind {
                 depth += 1;
                 last_layout = Some((info.clone(), depth));
             }
@@ -185,15 +182,15 @@ impl QueryJobId {
 }
 
 #[cfg(parallel_compiler)]
-struct QueryWaiter<D: DepKind> {
+struct QueryWaiter {
     query: Option<QueryJobId>,
     condvar: Condvar,
     span: Span,
-    cycle: Mutex<Option<CycleError<D>>>,
+    cycle: Mutex<Option<CycleError>>,
 }
 
 #[cfg(parallel_compiler)]
-impl<D: DepKind> QueryWaiter<D> {
+impl QueryWaiter {
     fn notify(&self, registry: &rayon_core::Registry) {
         rayon_core::mark_unblocked(registry);
         self.condvar.notify_one();
@@ -201,19 +198,19 @@ impl<D: DepKind> QueryWaiter<D> {
 }
 
 #[cfg(parallel_compiler)]
-struct QueryLatchInfo<D: DepKind> {
+struct QueryLatchInfo {
     complete: bool,
-    waiters: Vec<Arc<QueryWaiter<D>>>,
+    waiters: Vec<Arc<QueryWaiter>>,
 }
 
 #[cfg(parallel_compiler)]
 #[derive(Clone)]
-pub(super) struct QueryLatch<D: DepKind> {
-    info: Arc<Mutex<QueryLatchInfo<D>>>,
+pub(super) struct QueryLatch {
+    info: Arc<Mutex<QueryLatchInfo>>,
 }
 
 #[cfg(parallel_compiler)]
-impl<D: DepKind> QueryLatch<D> {
+impl QueryLatch {
     fn new() -> Self {
         QueryLatch {
             info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
@@ -221,11 +218,7 @@ impl<D: DepKind> QueryLatch<D> {
     }
 
     /// Awaits for the query job to complete.
-    pub(super) fn wait_on(
-        &self,
-        query: Option<QueryJobId>,
-        span: Span,
-    ) -> Result<(), CycleError<D>> {
+    pub(super) fn wait_on(&self, query: Option<QueryJobId>, span: Span) -> Result<(), CycleError> {
         let waiter =
             Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
         self.wait_on_inner(&waiter);
@@ -240,7 +233,7 @@ impl<D: DepKind> QueryLatch<D> {
     }
 
     /// Awaits the caller on this latch by blocking the current thread.
-    fn wait_on_inner(&self, waiter: &Arc<QueryWaiter<D>>) {
+    fn wait_on_inner(&self, waiter: &Arc<QueryWaiter>) {
         let mut info = self.info.lock();
         if !info.complete {
             // We push the waiter on to the `waiters` list. It can be accessed inside
@@ -274,7 +267,7 @@ impl<D: DepKind> QueryLatch<D> {
 
     /// Removes a single waiter from the list of waiters.
     /// This is used to break query cycles.
-    fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter<D>> {
+    fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter> {
         let mut info = self.info.lock();
         debug_assert!(!info.complete);
         // Remove the waiter from the list of waiters
@@ -296,14 +289,9 @@ type Waiter = (QueryJobId, usize);
 /// required information to resume the waiter.
 /// If all `visit` calls returns None, this function also returns None.
 #[cfg(parallel_compiler)]
-fn visit_waiters<F, D>(
-    query_map: &QueryMap<D>,
-    query: QueryJobId,
-    mut visit: F,
-) -> Option<Option<Waiter>>
+fn visit_waiters<F>(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option<Option<Waiter>>
 where
     F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>,
-    D: DepKind,
 {
     // Visit the parent query which is a non-resumable waiter since it's on the same stack
     if let Some(parent) = query.parent(query_map) {
@@ -332,8 +320,8 @@ where
 /// If a cycle is detected, this initial value is replaced with the span causing
 /// the cycle.
 #[cfg(parallel_compiler)]
-fn cycle_check<D: DepKind>(
-    query_map: &QueryMap<D>,
+fn cycle_check(
+    query_map: &QueryMap,
     query: QueryJobId,
     span: Span,
     stack: &mut Vec<(Span, QueryJobId)>,
@@ -373,8 +361,8 @@ fn cycle_check<D: DepKind>(
 /// from `query` without going through any of the queries in `visited`.
 /// This is achieved with a depth first search.
 #[cfg(parallel_compiler)]
-fn connected_to_root<D: DepKind>(
-    query_map: &QueryMap<D>,
+fn connected_to_root(
+    query_map: &QueryMap,
     query: QueryJobId,
     visited: &mut FxHashSet<QueryJobId>,
 ) -> bool {
@@ -396,10 +384,9 @@ fn connected_to_root<D: DepKind>(
 
 // Deterministically pick an query from a list
 #[cfg(parallel_compiler)]
-fn pick_query<'a, T, F, D>(query_map: &QueryMap<D>, queries: &'a [T], f: F) -> &'a T
+fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T
 where
     F: Fn(&T) -> (Span, QueryJobId),
-    D: DepKind,
 {
     // Deterministically pick an entry point
     // FIXME: Sort this instead
@@ -423,10 +410,10 @@ where
 /// If a cycle was not found, the starting query is removed from `jobs` and
 /// the function returns false.
 #[cfg(parallel_compiler)]
-fn remove_cycle<D: DepKind>(
-    query_map: &QueryMap<D>,
+fn remove_cycle(
+    query_map: &QueryMap,
     jobs: &mut Vec<QueryJobId>,
-    wakelist: &mut Vec<Arc<QueryWaiter<D>>>,
+    wakelist: &mut Vec<Arc<QueryWaiter>>,
 ) -> bool {
     let mut visited = FxHashSet::default();
     let mut stack = Vec::new();
@@ -528,7 +515,7 @@ fn remove_cycle<D: DepKind>(
 /// There may be multiple cycles involved in a deadlock, so this searches
 /// all active queries for cycles before finally resuming all the waiters at once.
 #[cfg(parallel_compiler)]
-pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Registry) {
+pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
     let on_panic = defer(|| {
         eprintln!("deadlock handler panicked, aborting process");
         process::abort();
@@ -566,9 +553,9 @@ pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Regis
 
 #[inline(never)]
 #[cold]
-pub(crate) fn report_cycle<'a, D: DepKind>(
+pub(crate) fn report_cycle<'a>(
     sess: &'a Session,
-    CycleError { usage, cycle: stack }: &CycleError<D>,
+    CycleError { usage, cycle: stack }: &CycleError,
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
     assert!(!stack.is_empty());
 
@@ -655,8 +642,10 @@ pub fn print_query_stack<Qcx: QueryContext>(
         if let Some(ref mut file) = file {
             let _ = writeln!(
                 file,
-                "#{} [{:?}] {}",
-                count_total, query_info.query.dep_kind, query_info.query.description
+                "#{} [{}] {}",
+                count_total,
+                qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name,
+                query_info.query.description
             );
         }
 
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index f7619d75be7..05dee9f12db 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -28,27 +28,27 @@ use thin_vec::ThinVec;
 ///
 /// This is mostly used in case of cycles for error reporting.
 #[derive(Clone, Debug)]
-pub struct QueryStackFrame<D: DepKind> {
+pub struct QueryStackFrame {
     pub description: String,
     span: Option<Span>,
     pub def_id: Option<DefId>,
     pub def_kind: Option<DefKind>,
     pub ty_adt_id: Option<DefId>,
-    pub dep_kind: D,
+    pub dep_kind: DepKind,
     /// This hash is used to deterministically pick
     /// a query to remove cycles in the parallel compiler.
     #[cfg(parallel_compiler)]
     hash: Hash64,
 }
 
-impl<D: DepKind> QueryStackFrame<D> {
+impl QueryStackFrame {
     #[inline]
     pub fn new(
         description: String,
         span: Option<Span>,
         def_id: Option<DefId>,
         def_kind: Option<DefKind>,
-        dep_kind: D,
+        dep_kind: DepKind,
         ty_adt_id: Option<DefId>,
         _hash: impl FnOnce() -> Hash64,
     ) -> Self {
@@ -106,7 +106,7 @@ pub trait QueryContext: HasDepContext {
     /// Get the query information from the TLS context.
     fn current_query_job(self) -> Option<QueryJobId>;
 
-    fn try_collect_active_jobs(self) -> Option<QueryMap<Self::DepKind>>;
+    fn try_collect_active_jobs(self) -> Option<QueryMap>;
 
     /// Load side effects associated to the node in the previous session.
     fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 07db15e6d8b..f93edffca79 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -2,8 +2,8 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
-use crate::dep_graph::{DepGraphData, HasDepContext};
+use crate::dep_graph::DepGraphData;
+use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
 #[cfg(parallel_compiler)]
@@ -30,24 +30,23 @@ use thin_vec::ThinVec;
 
 use super::QueryConfig;
 
-pub struct QueryState<K, D: DepKind> {
-    active: Sharded<FxHashMap<K, QueryResult<D>>>,
+pub struct QueryState<K> {
+    active: Sharded<FxHashMap<K, QueryResult>>,
 }
 
 /// Indicates the state of a query for a given key in a query map.
-enum QueryResult<D: DepKind> {
+enum QueryResult {
     /// An already executing query. The query job can be used to await for its completion.
-    Started(QueryJob<D>),
+    Started(QueryJob),
 
     /// The query panicked. Queries trying to wait on this will raise a fatal error which will
     /// silently panic.
     Poisoned,
 }
 
-impl<K, D> QueryState<K, D>
+impl<K> QueryState<K>
 where
     K: Eq + Hash + Copy + Debug,
-    D: DepKind,
 {
     pub fn all_inactive(&self) -> bool {
         self.active.lock_shards().all(|shard| shard.is_empty())
@@ -56,8 +55,8 @@ where
     pub fn try_collect_active_jobs<Qcx: Copy>(
         &self,
         qcx: Qcx,
-        make_query: fn(Qcx, K) -> QueryStackFrame<D>,
-        jobs: &mut QueryMap<D>,
+        make_query: fn(Qcx, K) -> QueryStackFrame,
+        jobs: &mut QueryMap,
     ) -> Option<()> {
         let mut active = Vec::new();
 
@@ -82,25 +81,25 @@ where
     }
 }
 
-impl<K, D: DepKind> Default for QueryState<K, D> {
-    fn default() -> QueryState<K, D> {
+impl<K> Default for QueryState<K> {
+    fn default() -> QueryState<K> {
         QueryState { active: Default::default() }
     }
 }
 
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
-struct JobOwner<'tcx, K, D: DepKind>
+struct JobOwner<'tcx, K>
 where
     K: Eq + Hash + Copy,
 {
-    state: &'tcx QueryState<K, D>,
+    state: &'tcx QueryState<K>,
     key: K,
 }
 
 #[cold]
 #[inline(never)]
-fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError<Qcx::DepKind>) -> Q::Value
+fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value
 where
     Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
@@ -112,7 +111,7 @@ where
 fn handle_cycle_error<Q, Qcx>(
     query: Q,
     qcx: Qcx,
-    cycle_error: &CycleError<Qcx::DepKind>,
+    cycle_error: &CycleError,
     mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
 ) -> Q::Value
 where
@@ -137,7 +136,7 @@ where
     }
 }
 
-impl<'tcx, K, D: DepKind> JobOwner<'tcx, K, D>
+impl<'tcx, K> JobOwner<'tcx, K>
 where
     K: Eq + Hash + Copy,
 {
@@ -169,10 +168,9 @@ where
     }
 }
 
-impl<'tcx, K, D> Drop for JobOwner<'tcx, K, D>
+impl<'tcx, K> Drop for JobOwner<'tcx, K>
 where
     K: Eq + Hash + Copy,
-    D: DepKind,
 {
     #[inline(never)]
     #[cold]
@@ -195,10 +193,10 @@ where
 }
 
 #[derive(Clone)]
-pub(crate) struct CycleError<D: DepKind> {
+pub(crate) struct CycleError {
     /// The query and related span that uses the cycle.
-    pub usage: Option<(Span, QueryStackFrame<D>)>,
-    pub cycle: Vec<QueryInfo<D>>,
+    pub usage: Option<(Span, QueryStackFrame)>,
+    pub cycle: Vec<QueryInfo>,
 }
 
 /// Checks if the query is already computed and in the cache.
@@ -248,7 +246,7 @@ fn wait_for_query<Q, Qcx>(
     qcx: Qcx,
     span: Span,
     key: Q::Key,
-    latch: QueryLatch<Qcx::DepKind>,
+    latch: QueryLatch,
     current: Option<QueryJobId>,
 ) -> (Q::Value, Option<DepNodeIndex>)
 where
@@ -296,7 +294,7 @@ fn try_execute_query<Q, Qcx, const INCR: bool>(
     qcx: Qcx,
     span: Span,
     key: Q::Key,
-    dep_node: Option<DepNode<Qcx::DepKind>>,
+    dep_node: Option<DepNode>,
 ) -> (Q::Value, Option<DepNodeIndex>)
 where
     Q: QueryConfig<Qcx>,
@@ -364,10 +362,10 @@ where
 fn execute_job<Q, Qcx, const INCR: bool>(
     query: Q,
     qcx: Qcx,
-    state: &QueryState<Q::Key, Qcx::DepKind>,
+    state: &QueryState<Q::Key>,
     key: Q::Key,
     id: QueryJobId,
-    dep_node: Option<DepNode<Qcx::DepKind>>,
+    dep_node: Option<DepNode>,
 ) -> (Q::Value, Option<DepNodeIndex>)
 where
     Q: QueryConfig<Qcx>,
@@ -474,9 +472,9 @@ where
 fn execute_job_incr<Q, Qcx>(
     query: Q,
     qcx: Qcx,
-    dep_graph_data: &DepGraphData<Qcx::DepKind>,
+    dep_graph_data: &DepGraphData<Qcx::Deps>,
     key: Q::Key,
-    mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
+    mut dep_node_opt: Option<DepNode>,
     job_id: QueryJobId,
 ) -> (Q::Value, DepNodeIndex)
 where
@@ -540,10 +538,10 @@ where
 #[inline(always)]
 fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
     query: Q,
-    dep_graph_data: &DepGraphData<Qcx::DepKind>,
+    dep_graph_data: &DepGraphData<Qcx::Deps>,
     qcx: Qcx,
     key: &Q::Key,
-    dep_node: &DepNode<Qcx::DepKind>,
+    dep_node: &DepNode,
 ) -> Option<(Q::Value, DepNodeIndex)>
 where
     Q: QueryConfig<Qcx>,
@@ -637,7 +635,7 @@ where
 #[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")]
 pub(crate) fn incremental_verify_ich<Tcx, V>(
     tcx: Tcx,
-    dep_graph_data: &DepGraphData<Tcx::DepKind>,
+    dep_graph_data: &DepGraphData<Tcx::Deps>,
     result: &V,
     prev_index: SerializedDepNodeIndex,
     hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
@@ -730,7 +728,7 @@ fn ensure_must_run<Q, Qcx>(
     qcx: Qcx,
     key: &Q::Key,
     check_cache: bool,
-) -> (bool, Option<DepNode<Qcx::DepKind>>)
+) -> (bool, Option<DepNode>)
 where
     Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
@@ -821,12 +819,8 @@ where
     Some(result)
 }
 
-pub fn force_query<Q, Qcx>(
-    query: Q,
-    qcx: Qcx,
-    key: Q::Key,
-    dep_node: DepNode<<Qcx as HasDepContext>::DepKind>,
-) where
+pub fn force_query<Q, Qcx>(query: Q, qcx: Qcx, key: Q::Key, dep_node: DepNode)
+where
     Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs
index 07c28fdb73b..8848fda9da3 100644
--- a/compiler/rustc_query_system/src/values.rs
+++ b/compiler/rustc_query_system/src/values.rs
@@ -1,14 +1,14 @@
 use rustc_span::ErrorGuaranteed;
 
-use crate::dep_graph::{DepContext, DepKind};
+use crate::dep_graph::DepContext;
 use crate::query::QueryInfo;
 
-pub trait Value<Tcx: DepContext, D: DepKind>: Sized {
-    fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], guar: ErrorGuaranteed) -> Self;
+pub trait Value<Tcx: DepContext>: Sized {
+    fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self;
 }
 
-impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T {
-    default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], _guar: ErrorGuaranteed) -> T {
+impl<Tcx: DepContext, T> Value<Tcx> for T {
+    default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> T {
         tcx.sess().abort_if_errors();
         // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
         // non-trivial to define it earlier.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 5a6def1958b..23f2be632b2 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -20,7 +20,7 @@ use std::collections::BTreeMap;
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::Hasher;
-use std::num::NonZeroUsize;
+use std::num::{IntErrorKind, NonZeroUsize};
 use std::path::PathBuf;
 use std::str;
 
@@ -387,7 +387,7 @@ mod desc {
         "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
     pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
     pub const parse_unpretty: &str = "`string` or `string=string`";
-    pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
+    pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
     pub const parse_trait_solver: &str =
         "one of the supported solver modes (`classic`, `next`, or `next-coherence`)";
     pub const parse_lto: &str =
@@ -986,10 +986,16 @@ mod parse {
 
     pub(crate) fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
         match v {
-            Some(s) => {
-                *slot = s.parse().ok();
-                slot.is_some()
-            }
+            Some(s) => match s.parse() {
+                Ok(val) => {
+                    *slot = Some(val);
+                    true
+                }
+                Err(e) => {
+                    *slot = None;
+                    e.kind() == &IntErrorKind::Zero
+                }
+            },
             None => {
                 *slot = NonZeroUsize::new(1);
                 true
@@ -1846,7 +1852,8 @@ written to standard error output)"),
     trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
     treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED],
-        "treat error number `val` that occurs as bug"),
+        "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \
+        default if specified without a value: 1 - treat the first error as bug)"),
     trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
         "in diagnostics, use heuristics to shorten paths referring to items"),
     tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 93b5b9654d3..ad5f17cab6c 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -14,8 +14,8 @@ use crate::stable_mir::ty::{
 };
 use crate::stable_mir::{self, CompilerError, Context};
 use rustc_hir as hir;
+use rustc_middle::mir;
 use rustc_middle::mir::interpret::{alloc_range, AllocId};
-use rustc_middle::mir::{self, ConstantKind};
 use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_span::ErrorGuaranteed;
@@ -539,14 +539,14 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
     }
 }
 
-impl<'tcx> Stable<'tcx> for mir::Constant<'tcx> {
+impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> {
     type T = stable_mir::mir::Constant;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         stable_mir::mir::Constant {
             span: self.span.stable(tables),
             user_ty: self.user_ty.map(|u| u.as_usize()).or(None),
-            literal: self.literal.stable(tables),
+            literal: self.const_.stable(tables),
         }
     }
 }
@@ -1247,13 +1247,13 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> {
+impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
     type T = stable_mir::ty::Const;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         match *self {
-            ConstantKind::Ty(c) => c.stable(tables),
-            ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const {
+            mir::Const::Ty(c) => c.stable(tables),
+            mir::Const::Unevaluated(unev_const, ty) => stable_mir::ty::Const {
                 literal: stable_mir::ty::ConstantKind::Unevaluated(
                     stable_mir::ty::UnevaluatedConst {
                         def: tables.const_def(unev_const.def),
@@ -1263,7 +1263,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> {
                 ),
                 ty: tables.intern_ty(ty),
             },
-            ConstantKind::Val(val, ty) => stable_mir::ty::Const {
+            mir::Const::Val(val, ty) => stable_mir::ty::Const {
                 literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
                     ty, val, tables,
                 )),
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 77457c8daaa..d1f2c1b27fd 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -118,7 +118,7 @@ fn encode_const<'tcx>(
             // bool value false is encoded as 0 and true as 1.
             match c.ty().kind() {
                 ty::Int(ity) => {
-                    let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
+                    let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all());
                     let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
                     if val < 0 {
                         s.push('n');
@@ -126,7 +126,7 @@ fn encode_const<'tcx>(
                     let _ = write!(s, "{val}");
                 }
                 ty::Uint(_) => {
-                    let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
+                    let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all());
                     let _ = write!(s, "{val}");
                 }
                 ty::Bool => {
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 2550570af65..e9a7d0be4b4 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -594,7 +594,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
             ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
                 self = ty.print(self)?;
 
-                let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty);
+                let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all());
 
                 // Negative integer values are mangled using `n` as a "sign prefix".
                 if let ty::Int(ity) = ty.kind() {
diff --git a/compiler/rustc_target/src/spec/hurd_base.rs b/compiler/rustc_target/src/spec/hurd_base.rs
new file mode 100644
index 00000000000..76f8223c0e4
--- /dev/null
+++ b/compiler/rustc_target/src/spec/hurd_base.rs
@@ -0,0 +1,15 @@
+use crate::spec::{cvs, RelroLevel, TargetOptions};
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        os: "hurd".into(),
+        dynamic_linking: true,
+        families: cvs!["unix"],
+        has_rpath: true,
+        position_independent_executables: true,
+        relro_level: RelroLevel::Full,
+        has_thread_local: true,
+        crt_static_respected: true,
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/hurd_gnu_base.rs b/compiler/rustc_target/src/spec/hurd_gnu_base.rs
new file mode 100644
index 00000000000..b9cf26d9380
--- /dev/null
+++ b/compiler/rustc_target/src/spec/hurd_gnu_base.rs
@@ -0,0 +1,5 @@
+use crate::spec::TargetOptions;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions { env: "gnu".into(), ..super::hurd_base::opts() }
+}
diff --git a/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs
new file mode 100644
index 00000000000..29f80360138
--- /dev/null
+++ b/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs
@@ -0,0 +1,19 @@
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
+
+pub fn target() -> Target {
+    let mut base = super::hurd_gnu_base::opts();
+    base.cpu = "pentiumpro".into();
+    base.max_atomic_width = Some(64);
+    base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
+    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+
+    Target {
+        llvm_target: "i686-unknown-hurd-gnu".into(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .into(),
+        arch: "x86".into(),
+        options: base,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 8aa72797a0d..60fe98e5045 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -71,6 +71,8 @@ mod freebsd_base;
 mod fuchsia_base;
 mod haiku_base;
 mod hermit_base;
+mod hurd_base;
+mod hurd_gnu_base;
 mod illumos_base;
 mod l4re_base;
 mod linux_base;
@@ -1367,6 +1369,8 @@ supported_targets! {
     ("i686-unknown-haiku", i686_unknown_haiku),
     ("x86_64-unknown-haiku", x86_64_unknown_haiku),
 
+    ("i686-unknown-hurd-gnu", i686_unknown_hurd_gnu),
+
     ("aarch64-apple-darwin", aarch64_apple_darwin),
     ("x86_64-apple-darwin", x86_64_apple_darwin),
     ("x86_64h-apple-darwin", x86_64h_apple_darwin),
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 16de518e8e0..728d0fc1ae7 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -8,7 +8,7 @@ use cache::ProvisionalCache;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::Idx;
 use rustc_index::IndexVec;
-use rustc_middle::dep_graph::DepKind;
+use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::traits::solve::inspect::CacheHit;
 use rustc_middle::traits::solve::CacheData;
 use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
@@ -287,7 +287,7 @@ impl<'tcx> SearchGraph<'tcx> {
         // Everything that affects the `result` should be performed within this
         // `with_anon_task` closure.
         let ((final_entry, result), dep_node) =
-            tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || {
+            tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || {
                 // When we encounter a coinductive cycle, we have to fetch the
                 // result of that cycle while we are still computing it. Because
                 // of this we continuously recompute the cycle until the result
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 7d754cbafa3..d3e0d3b8b18 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -987,6 +987,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         }
 
                         self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);
+                        self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref);
 
                         // Return early if the trait is Debug or Display and the invocation
                         // originates within a standard library macro, because the output
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 4086db2ab55..d645dc033b8 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
@@ -104,7 +104,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
                 self.describe_generator(*body_id).or_else(|| {
                     Some(match sig.header {
-                        hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function",
+                        hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => {
+                            "an async function"
+                        }
                         _ => "a function",
                     })
                 })
@@ -118,7 +120,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 ..
             }) => self.describe_generator(*body_id).or_else(|| {
                 Some(match sig.header {
-                    hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method",
+                    hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => "an async method",
                     _ => "a method",
                 })
             }),
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 a08ebe5a9ea..cd1dadde1ba 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -414,6 +414,12 @@ pub trait TypeErrCtxtExt<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         cause: &ObligationCause<'tcx>,
     );
+
+    fn suggest_desugaring_async_fn_in_trait(
+        &self,
+        err: &mut Diagnostic,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+    );
 }
 
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
@@ -2711,6 +2717,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             | ObligationCauseCode::IfExpressionWithNoElse
             | ObligationCauseCode::MainFunctionType
             | ObligationCauseCode::StartFunctionType
+            | ObligationCauseCode::LangFunctionType(_)
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver
             | ObligationCauseCode::ReturnNoExpression
@@ -4100,6 +4107,136 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             });
         }
     }
+
+    fn suggest_desugaring_async_fn_in_trait(
+        &self,
+        err: &mut Diagnostic,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+    ) {
+        // Don't suggest if RTN is active -- we should prefer a where-clause bound instead.
+        if self.tcx.features().return_type_notation {
+            return;
+        }
+
+        let trait_def_id = trait_ref.def_id();
+
+        // Only suggest specifying auto traits
+        if !self.tcx.trait_is_auto(trait_def_id) {
+            return;
+        }
+
+        // Look for an RPITIT
+        let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else {
+            return;
+        };
+        let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
+            self.tcx.opt_rpitit_info(alias_ty.def_id)
+        else {
+            return;
+        };
+
+        let auto_trait = self.tcx.def_path_str(trait_def_id);
+        // ... which is a local function
+        let Some(fn_def_id) = fn_def_id.as_local() else {
+            // If it's not local, we can at least mention that the method is async, if it is.
+            if self.tcx.asyncness(fn_def_id).is_async() {
+                err.span_note(
+                    self.tcx.def_span(fn_def_id),
+                    format!(
+                        "`{}::{}` is an `async fn` in trait, which does not \
+                    automatically imply that its future is `{auto_trait}`",
+                        alias_ty.trait_ref(self.tcx),
+                        self.tcx.item_name(fn_def_id)
+                    ),
+                );
+            }
+            return;
+        };
+        let Some(hir::Node::TraitItem(item)) = self.tcx.hir().find_by_def_id(fn_def_id) else {
+            return;
+        };
+
+        // ... whose signature is `async` (i.e. this is an AFIT)
+        let (sig, body) = item.expect_fn();
+        let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
+            return;
+        };
+        let Ok(async_span) =
+            self.tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace())
+        else {
+            return;
+        };
+        let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
+            sig.decl.output
+        else {
+            // This should never happen, but let's not ICE.
+            return;
+        };
+
+        // Check that this is *not* a nested `impl Future` RPIT in an async fn
+        // (i.e. `async fn foo() -> impl Future`)
+        if def.owner_id.to_def_id() != opaque_def_id {
+            return;
+        }
+
+        let future = self.tcx.hir().item(*def).expect_opaque_ty();
+        let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else {
+            // `async fn` should always lower to a lang item bound... but don't ICE.
+            return;
+        };
+        let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
+            generics.bindings.get(0).map(|binding| binding.kind)
+        else {
+            // Also should never happen.
+            return;
+        };
+
+        let function_name = self.tcx.def_path_str(fn_def_id);
+
+        let mut sugg = if future_output_ty.span.is_empty() {
+            vec![
+                (async_span, String::new()),
+                (
+                    future_output_ty.span,
+                    format!(" -> impl std::future::Future<Output = ()> + {auto_trait}"),
+                ),
+            ]
+        } else {
+            vec![
+                (
+                    future_output_ty.span.shrink_to_lo(),
+                    "impl std::future::Future<Output = ".to_owned(),
+                ),
+                (future_output_ty.span.shrink_to_hi(), format!("> + {auto_trait}")),
+                (async_span, String::new()),
+            ]
+        };
+
+        // If there's a body, we also need to wrap it in `async {}`
+        if let hir::TraitFn::Provided(body) = body {
+            let body = self.tcx.hir().body(*body);
+            let body_span = body.value.span;
+            let body_span_without_braces =
+                body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
+            if body_span_without_braces.is_empty() {
+                sugg.push((body_span_without_braces, " async {} ".to_owned()));
+            } else {
+                sugg.extend([
+                    (body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
+                    (body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
+                ]);
+            }
+        }
+
+        err.multipart_suggestion(
+            format!(
+                "`{auto_trait}` can be made part of the associated future's \
+                guarantees for all implementations of `{function_name}`"
+            ),
+            sugg,
+            Applicability::MachineApplicable,
+        );
+    }
 }
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 24d31633850..dcf41c3774f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -35,7 +35,8 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::traits::TraitObligation;
-use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
+use rustc_middle::dep_graph::dep_kinds;
+use rustc_middle::dep_graph::DepNodeIndex;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -1435,7 +1436,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         OP: FnOnce(&mut Self) -> R,
     {
         let (result, dep_node) =
-            self.tcx().dep_graph.with_anon_task(self.tcx(), DepKind::TraitSelect, || op(self));
+            self.tcx().dep_graph.with_anon_task(self.tcx(), dep_kinds::TraitSelect, || op(self));
         self.tcx().dep_graph.read_index(dep_node);
         (result, dep_node)
     }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 2288d36df17..6c23589b39a 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -296,9 +296,12 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<EarlyBinder<Ty<'
 }
 
 /// Check if a function is async.
-fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::IsAsync {
+fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness {
     let node = tcx.hir().get_by_def_id(def_id);
-    node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness)
+    node.fn_sig().map_or(ty::Asyncness::No, |sig| match sig.header.asyncness {
+        hir::IsAsync::Async(_) => ty::Asyncness::Yes,
+        hir::IsAsync::NotAsync => ty::Asyncness::No,
+    })
 }
 
 fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32> {
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index b5458e667ed..8b04bafcda5 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -195,6 +195,7 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(not(bootstrap), feature(effects))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs
index 21c23dabfc2..34dfa9e4c51 100644
--- a/library/core/src/ops/drop.rs
+++ b/library/core/src/ops/drop.rs
@@ -202,7 +202,7 @@
 /// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle
 #[lang = "drop"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
+// FIXME(effects) #[const_trait]
 pub trait Drop {
     /// Executes the destructor for this type.
     ///
diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs
index 67c8245f0bf..20f0bba4c13 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -72,7 +72,7 @@ use crate::marker::Tuple;
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
+// FIXME(effects) #[const_trait]
 pub trait Fn<Args: Tuple>: FnMut<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
@@ -159,7 +159,7 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
+// FIXME(effects) #[const_trait]
 pub trait FnMut<Args: Tuple>: FnOnce<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
@@ -238,7 +238,7 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
+// FIXME(effects) #[const_trait]
 pub trait FnOnce<Args: Tuple> {
     /// The returned type after the call operator is used.
     #[lang = "fn_once_output"]
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 281f8c1e166..e6cdffd96af 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -234,7 +234,8 @@ fn panic_in_cleanup() -> ! {
 #[rustc_const_unstable(feature = "core_panic", issue = "none")]
 pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if let Some(msg) = fmt.as_str() {
-        panic_str(msg);
+        // The panic_display function is hooked by const eval.
+        panic_display(&msg);
     } else {
         // SAFETY: This is only evaluated at compile time, which reliably
         // handles this UB (in case this branch turns out to be reachable
diff --git a/library/std/build.rs b/library/std/build.rs
index a81c45609ea..e5509504b84 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -38,6 +38,7 @@ fn main() {
         || target.contains("vita")
         || target.contains("nto")
         || target.contains("xous")
+        || target.contains("hurd")
         // See src/bootstrap/synthetic_targets.rs
         || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
     {
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index eca64fb6063..7582c7444f0 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -5,7 +5,7 @@
 //! the [`Read`] and [`Write`] traits, which provide the
 //! most general interface for reading and writing input and output.
 //!
-//! # Read and Write
+//! ## Read and Write
 //!
 //! Because they are traits, [`Read`] and [`Write`] are implemented by a number
 //! of other types, and you can implement them for your types too. As such,
@@ -238,6 +238,47 @@
 //! contract. The implementation of many of these functions are subject to change over
 //! time and may call fewer or more syscalls/library functions.
 //!
+//! ## I/O Safety
+//!
+//! Rust follows an I/O safety discipline that is comparable to its memory safety discipline. This
+//! means that file descriptors can be *exclusively owned*. (Here, "file descriptor" is meant to
+//! subsume similar concepts that exist across a wide range of operating systems even if they might
+//! use a different name, such as "handle".) An exclusively owned file descriptor is one that no
+//! other code is allowed to access in any way, but the owner is allowed to access and even close
+//! it any time. A type that owns its file descriptor should usually close it in its `drop`
+//! function. Types like [`File`] own their file descriptor. Similarly, file descriptors
+//! can be *borrowed*, granting the temporary right to perform operations on this file descriptor.
+//! This indicates that the file descriptor will not be closed for the lifetime of the borrow, but
+//! it does *not* imply any right to close this file descriptor, since it will likely be owned by
+//! someone else.
+//!
+//! The platform-specific parts of the Rust standard library expose types that reflect these
+//! concepts, see [`os::unix`] and [`os::windows`].
+//!
+//! To uphold I/O safety, it is crucial that no code acts on file descriptors it does not own or
+//! borrow, and no code closes file descriptors it does not own. In other words, a safe function
+//! that takes a regular integer, treats it as a file descriptor, and acts on it, is *unsound*.
+//!
+//! Not upholding I/O safety and acting on a file descriptor without proof of ownership can lead to
+//! misbehavior and even Undefined Behavior in code that relies on ownership of its file
+//! descriptors: a closed file descriptor could be re-allocated, so the original owner of that file
+//! descriptor is now working on the wrong file. Some code might even rely on fully encapsulating
+//! its file descriptors with no operations being performed by any other part of the program.
+//!
+//! Note that exclusive ownership of a file descriptor does *not* imply exclusive ownership of the
+//! underlying kernel object that the file descriptor references (also called "file description" on
+//! some operating systems). File descriptors basically work like [`Arc`]: when you receive an owned
+//! file descriptor, you cannot know whether there are any other file descriptors that reference the
+//! same kernel object. However, when you create a new kernel object, you know that you are holding
+//! the only reference to it. Just be careful not to lend it to anyone, since they can obtain a
+//! clone and then you can no longer know what the reference count is! In that sense, [`OwnedFd`] is
+//! like `Arc` and [`BorrowedFd<'a>`] is like `&'a Arc` (and similar for the Windows types). In
+//! particular, given a `BorrowedFd<'a>`, you are not allowed to close the file descriptor -- just
+//! like how, given a `&'a Arc`, you are not allowed to decrement the reference count and
+//! potentially free the underlying object. There is no equivalent to `Box` for file descriptors in
+//! the standard library (that would be a type that guarantees that the reference count is `1`),
+//! however, it would be possible for a crate to define a type with those semantics.
+//!
 //! [`File`]: crate::fs::File
 //! [`TcpStream`]: crate::net::TcpStream
 //! [`io::stdout`]: stdout
@@ -245,6 +286,11 @@
 //! [`?` operator]: ../../book/appendix-02-operators.html
 //! [`Result`]: crate::result::Result
 //! [`.unwrap()`]: crate::result::Result::unwrap
+//! [`os::unix`]: ../os/unix/io/index.html
+//! [`os::windows`]: ../os/windows/io/index.html
+//! [`OwnedFd`]: ../os/fd/struct.OwnedFd.html
+//! [`BorrowedFd<'a>`]: ../os/fd/struct.BorrowedFd.html
+//! [`Arc`]: crate::sync::Arc
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 2180d2974d5..81106d6c62c 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -15,8 +15,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 /// A borrowed file descriptor.
 ///
-/// This has a lifetime parameter to tie it to the lifetime of something that
-/// owns the file descriptor.
+/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
+/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
+/// descriptor.
 ///
 /// This uses `repr(transparent)` and has the representation of a host file
 /// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -42,7 +43,8 @@ pub struct BorrowedFd<'fd> {
 
 /// An owned file descriptor.
 ///
-/// This closes the file descriptor on drop.
+/// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file
+/// descriptor.
 ///
 /// This uses `repr(transparent)` and has the representation of a host file
 /// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -155,7 +157,9 @@ impl FromRawFd for OwnedFd {
     /// # Safety
     ///
     /// The resource pointed to by `fd` must be open and suitable for assuming
-    /// ownership. The resource must not require any cleanup other than `close`.
+    /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
+    ///
+    /// [io-safety]: io#io-safety
     #[inline]
     unsafe fn from_raw_fd(fd: RawFd) -> Self {
         assert_ne!(fd, u32::MAX as RawFd);
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 592e072ad90..ef896ea95c9 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -84,7 +84,10 @@ pub trait FromRawFd {
     ///
     /// # Safety
     ///
-    /// The `fd` passed in must be a valid and open file descriptor.
+    /// The `fd` passed in must be an [owned file descriptor][io-safety];
+    /// in particular, it must be open.
+    ///
+    /// [io-safety]: io#io-safety
     ///
     /// # Example
     ///
diff --git a/library/std/src/os/fortanix_sgx/io.rs b/library/std/src/os/fortanix_sgx/io.rs
index 7223ade6815..7e57435b65c 100644
--- a/library/std/src/os/fortanix_sgx/io.rs
+++ b/library/std/src/os/fortanix_sgx/io.rs
@@ -31,15 +31,22 @@ pub trait FromRawFd {
     /// Constructs a new instance of `Self` from the given raw file
     /// descriptor and metadata.
     ///
-    /// This function **consumes ownership** of the specified file
-    /// descriptor. The returned object will take responsibility for closing
-    /// it when the object goes out of scope.
+    /// This function is typically used to **consume ownership** of the
+    /// specified file descriptor. When used in this way, the returned object
+    /// will take responsibility for closing it when the object goes out of
+    /// scope.
     ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
+    /// However, consuming ownership is not strictly required. Use a
+    /// [`From<OwnedFd>::from`] implementation for an API which strictly
+    /// consumes ownership.
+    ///
+    /// # Safety
+    ///
+    /// The `fd` passed in must be an [owned file descriptor][io-safety];
+    /// in particular, it must be open.
+    // FIXME: say something about `metadata`.
+    ///
+    /// [io-safety]: io#io-safety
     #[unstable(feature = "sgx_platform", issue = "56975")]
     unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self;
 }
diff --git a/library/std/src/os/hurd/fs.rs b/library/std/src/os/hurd/fs.rs
new file mode 100644
index 00000000000..00ff1560f31
--- /dev/null
+++ b/library/std/src/os/hurd/fs.rs
@@ -0,0 +1,348 @@
+//! Hurd-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Returns the device ID on which this file resides.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_dev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+    /// Returns the inode number.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ino());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+    /// Returns the file type and mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mode());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mode(&self) -> u32;
+    /// Returns the number of hard links to file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_nlink());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+    /// Returns the user ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_uid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+    /// Returns the group ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_gid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+    /// Returns the device ID that this file represents. Only relevant for special file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_rdev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+    ///
+    /// The size of a symbolic link is the length of the pathname it contains,
+    /// without a terminating null byte.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_size());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+    /// Returns the last access time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+    /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+    ///
+    /// [`st_atime`]: Self::st_atime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+    /// Returns the last modification time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+    /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+    ///
+    /// [`st_mtime`]: Self::st_mtime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+    /// Returns the last status change time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+    /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+    ///
+    /// [`st_ctime`]: Self::st_ctime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+    /// Returns the "preferred" block size for efficient filesystem I/O.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blksize());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+    /// Returns the number of blocks allocated to the file, 512-byte units.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::hurd::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blocks());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_fsid as u64
+    }
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_sec as i64
+    }
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_nsec as i64
+    }
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_sec as i64
+    }
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_nsec as i64
+    }
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_sec as i64
+    }
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_nsec as i64
+    }
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+}
diff --git a/library/std/src/os/hurd/mod.rs b/library/std/src/os/hurd/mod.rs
new file mode 100644
index 00000000000..aee86c7f616
--- /dev/null
+++ b/library/std/src/os/hurd/mod.rs
@@ -0,0 +1,6 @@
+//! Hurd-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/hurd/raw.rs b/library/std/src/os/hurd/raw.rs
new file mode 100644
index 00000000000..fa266663528
--- /dev/null
+++ b/library/std/src/os/hurd/raw.rs
@@ -0,0 +1,33 @@
+//! Hurd-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+    since = "1.8.0",
+    note = "these type aliases are no longer supported by \
+              the standard library, the `libc` crate on \
+              crates.io should be used instead for the correct \
+              definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::{c_long, c_uint, c_ulong};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = c_long;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = c_uint;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = c_long;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_long;
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index de6d784c65b..24d16e64c86 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -117,6 +117,8 @@ pub mod haiku;
 pub mod hermit;
 #[cfg(target_os = "horizon")]
 pub mod horizon;
+#[cfg(target_os = "hurd")]
+pub mod hurd;
 #[cfg(target_os = "illumos")]
 pub mod illumos;
 #[cfg(target_os = "ios")]
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index 33cc5a015b5..f82034663d4 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -27,15 +27,21 @@ pub trait FromRawFd {
     /// Constructs a new instance of `Self` from the given raw file
     /// descriptor.
     ///
-    /// This function **consumes ownership** of the specified file
-    /// descriptor. The returned object will take responsibility for closing
-    /// it when the object goes out of scope.
+    /// This function is typically used to **consume ownership** of the
+    /// specified file descriptor. When used in this way, the returned object
+    /// will take responsibility for closing it when the object goes out of
+    /// scope.
     ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
+    /// However, consuming ownership is not strictly required. Use a
+    /// [`From<OwnedFd>::from`] implementation for an API which strictly
+    /// consumes ownership.
+    ///
+    /// # Safety
+    ///
+    /// The `fd` passed in must be an [owned file descriptor][io-safety];
+    /// in particular, it must be open.
+    ///
+    /// [io-safety]: io#io-safety
     unsafe fn from_raw_fd(fd: RawFd) -> Self;
 }
 
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
index 25b5dbff14f..c12d89ed637 100644
--- a/library/std/src/os/unix/io/mod.rs
+++ b/library/std/src/os/unix/io/mod.rs
@@ -6,7 +6,7 @@
 //!
 //! This module provides three types for representing file descriptors,
 //! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers:
+//! analogous to types used for representing pointers. These types reflect the Unix version of [I/O safety].
 //!
 //! | Type               | Analogous to |
 //! | ------------------ | ------------ |
@@ -65,15 +65,16 @@
 //! to be opened and read from or written must be `unsafe`. Rust's safety guarantees
 //! only cover what the program itself can do, and not what entities outside
 //! the program can do to it. `/proc/self/mem` is considered to be such an
-//! external entity, along with debugging interfaces, and people with physical access to
-//! the hardware. This is true even in cases where the program is controlling
-//! the external entity.
+//! external entity, along with `/proc/self/fd/*`, debugging interfaces, and people with physical
+//! access to the hardware. This is true even in cases where the program is controlling the external
+//! entity.
 //!
 //! If you desire to comprehensively prevent programs from reaching out and
 //! causing external entities to reach back in and violate memory safety, it's
 //! necessary to use *sandboxing*, which is outside the scope of `std`.
 //!
 //! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
+//! [I/O safety]: crate::io#io-safety
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 401ec1e7a01..3724e90afbd 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -53,6 +53,8 @@ mod platform {
     pub use crate::os::haiku::*;
     #[cfg(target_os = "horizon")]
     pub use crate::os::horizon::*;
+    #[cfg(target_os = "hurd")]
+    pub use crate::os::hurd::*;
     #[cfg(target_os = "illumos")]
     pub use crate::os::illumos::*;
     #[cfg(target_os = "ios")]
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
index e2a401fb696..3d4bb96d458 100644
--- a/library/std/src/os/windows/io/mod.rs
+++ b/library/std/src/os/windows/io/mod.rs
@@ -6,7 +6,7 @@
 //!
 //! This module provides three types for representing raw handles and sockets
 //! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers:
+//! analogous to types used for representing pointers. These types reflect the Windows version of [I/O safety].
 //!
 //! | Type                   | Analogous to |
 //! | ---------------------- | ------------ |
@@ -47,6 +47,7 @@
 //!
 //! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
 //! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
+//! [I/O safety]: crate::io#io-safety
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
index 1759e2e7f3f..770583a9ce3 100644
--- a/library/std/src/os/windows/io/raw.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -62,7 +62,7 @@ pub trait FromRawHandle {
     /// # Safety
     ///
     /// The `handle` passed in must:
-    ///   - be a valid an open handle,
+    ///   - be an [owned handle][io-safety]; in particular, it must be open.
     ///   - be a handle for a resource that may be freed via [`CloseHandle`]
     ///     (as opposed to `RegCloseKey` or other close functions).
     ///
@@ -71,6 +71,7 @@ pub trait FromRawHandle {
     ///
     /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+    /// [io-safety]: io#io-safety
     #[stable(feature = "from_raw_os", since = "1.1.0")]
     unsafe fn from_raw_handle(handle: RawHandle) -> Self;
 }
@@ -207,10 +208,11 @@ pub trait FromRawSocket {
     /// # Safety
     ///
     /// The `socket` passed in must:
-    ///   - be a valid an open socket,
+    ///   - be an [owned socket][io-safety]; in particular, it must be open.
     ///   - be a socket that may be freed via [`closesocket`].
     ///
     /// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket
+    /// [io-safety]: io#io-safety
     #[stable(feature = "from_raw_os", since = "1.1.0")]
     unsafe fn from_raw_socket(sock: RawSocket) -> Self;
 }
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 5df1105e264..948862c2a7d 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -789,7 +789,7 @@ impl Command {
     /// or [`Command::envs`]. In addition, it will prevent the spawned child process from inheriting
     /// any environment variable from its parent process.
     ///
-    /// After calling [`Command::env_remove`], the iterator from [`Command::get_envs`] will be
+    /// After calling [`Command::env_clear`], the iterator from [`Command::get_envs`] will be
     /// empty.
     ///
     /// You can use [`Command::env_remove`] to clear a single mapping.
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 00636237288..07d4de5c1a2 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -537,7 +537,7 @@ fn env_empty() {
 #[test]
 #[cfg(not(windows))]
 #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
-fn main() {
+fn debug_print() {
     const PIDFD: &'static str =
         if cfg!(target_os = "linux") { "    create_pidfd: false,\n" } else { "" };
 
@@ -626,6 +626,51 @@ fn main() {
 {PIDFD}}}"#
         )
     );
+
+    let mut command_with_removed_env = Command::new("boring-name");
+    command_with_removed_env.env_remove("FOO").env_remove("BAR");
+    assert_eq!(format!("{command_with_removed_env:?}"), r#"env -u BAR -u FOO "boring-name""#);
+    assert_eq!(
+        format!("{command_with_removed_env:#?}"),
+        format!(
+            r#"Command {{
+    program: "boring-name",
+    args: [
+        "boring-name",
+    ],
+    env: CommandEnv {{
+        clear: false,
+        vars: {{
+            "BAR": None,
+            "FOO": None,
+        }},
+    }},
+{PIDFD}}}"#
+        )
+    );
+
+    let mut command_with_cleared_env = Command::new("boring-name");
+    command_with_cleared_env.env_clear().env("BAR", "val").env_remove("FOO");
+    assert_eq!(format!("{command_with_cleared_env:?}"), r#"env -i BAR="val" "boring-name""#);
+    assert_eq!(
+        format!("{command_with_cleared_env:#?}"),
+        format!(
+            r#"Command {{
+    program: "boring-name",
+    args: [
+        "boring-name",
+    ],
+    env: CommandEnv {{
+        clear: true,
+        vars: {{
+            "BAR": Some(
+                "val",
+            ),
+        }},
+    }},
+{PIDFD}}}"#
+        )
+    );
 }
 
 // See issue #91991
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index eafd6821f54..19334e2aff2 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -71,6 +71,7 @@ impl DoubleEndedIterator for Args {
     target_os = "vxworks",
     target_os = "horizon",
     target_os = "nto",
+    target_os = "hurd",
 ))]
 mod imp {
     use super::Args;
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index 929e9dae738..c6d8578a629 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -152,6 +152,17 @@ pub mod os {
     pub const EXE_EXTENSION: &str = "elf";
 }
 
+#[cfg(target_os = "hurd")]
+pub mod os {
+    pub const FAMILY: &str = "unix";
+    pub const OS: &str = "hurd";
+    pub const DLL_PREFIX: &str = "lib";
+    pub const DLL_SUFFIX: &str = ".so";
+    pub const DLL_EXTENSION: &str = "so";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
+
 #[cfg(target_os = "vita")]
 pub mod os {
     pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 85e020ae413..6c4f408426a 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -13,14 +13,16 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
     target_os = "android",
     target_os = "linux",
     target_os = "emscripten",
-    target_os = "l4re"
+    target_os = "l4re",
+    target_os = "hurd",
 ))]
 use libc::off64_t;
 #[cfg(not(any(
     target_os = "linux",
     target_os = "emscripten",
     target_os = "l4re",
-    target_os = "android"
+    target_os = "android",
+    target_os = "hurd",
 )))]
 use libc::off_t as off64_t;
 
@@ -124,9 +126,9 @@ impl FileDesc {
     }
 
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        #[cfg(not(any(target_os = "linux", target_os = "android")))]
+        #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))]
         use libc::pread as pread64;
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))]
         use libc::pread64;
 
         unsafe {
@@ -160,6 +162,7 @@ impl FileDesc {
         target_os = "emscripten",
         target_os = "freebsd",
         target_os = "fuchsia",
+        target_os = "hurd",
         target_os = "illumos",
         target_os = "linux",
         target_os = "netbsd",
@@ -181,6 +184,7 @@ impl FileDesc {
         target_os = "emscripten",
         target_os = "freebsd",
         target_os = "fuchsia",
+        target_os = "hurd",
         target_os = "illumos",
         target_os = "ios",
         target_os = "tvos",
@@ -281,9 +285,9 @@ impl FileDesc {
     }
 
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        #[cfg(not(any(target_os = "linux", target_os = "android")))]
+        #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))]
         use libc::pwrite as pwrite64;
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))]
         use libc::pwrite64;
 
         unsafe {
@@ -301,6 +305,7 @@ impl FileDesc {
         target_os = "emscripten",
         target_os = "freebsd",
         target_os = "fuchsia",
+        target_os = "hurd",
         target_os = "illumos",
         target_os = "linux",
         target_os = "netbsd",
@@ -322,6 +327,7 @@ impl FileDesc {
         target_os = "emscripten",
         target_os = "freebsd",
         target_os = "fuchsia",
+        target_os = "hurd",
         target_os = "illumos",
         target_os = "ios",
         target_os = "tvos",
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 61ea87a5b0c..764e1f25790 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -39,9 +39,14 @@ use libc::{c_int, mode_t};
     all(target_os = "linux", target_env = "gnu")
 ))]
 use libc::c_char;
-#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
+#[cfg(any(
+    target_os = "linux",
+    target_os = "emscripten",
+    target_os = "android",
+    target_os = "hurd",
+))]
 use libc::dirfd;
-#[cfg(any(target_os = "linux", target_os = "emscripten"))]
+#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd"))]
 use libc::fstatat64;
 #[cfg(any(
     target_os = "android",
@@ -53,7 +58,7 @@ use libc::fstatat64;
     target_os = "vita",
 ))]
 use libc::readdir as readdir64;
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "hurd"))]
 use libc::readdir64;
 #[cfg(any(target_os = "emscripten", target_os = "l4re"))]
 use libc::readdir64_r;
@@ -68,6 +73,7 @@ use libc::readdir64_r;
     target_os = "redox",
     target_os = "nto",
     target_os = "vita",
+    target_os = "hurd",
 )))]
 use libc::readdir_r as readdir64_r;
 #[cfg(target_os = "android")]
@@ -79,13 +85,19 @@ use libc::{
     target_os = "linux",
     target_os = "emscripten",
     target_os = "l4re",
-    target_os = "android"
+    target_os = "android",
+    target_os = "hurd",
 )))]
 use libc::{
     dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64,
     lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
 };
-#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
+#[cfg(any(
+    target_os = "linux",
+    target_os = "emscripten",
+    target_os = "l4re",
+    target_os = "hurd"
+))]
 use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
 
 pub use crate::sys_common::fs::try_exists;
@@ -277,7 +289,8 @@ unsafe impl Sync for Dir {}
     target_os = "fuchsia",
     target_os = "redox",
     target_os = "nto",
-    target_os = "vita"
+    target_os = "vita",
+    target_os = "hurd",
 ))]
 pub struct DirEntry {
     dir: Arc<InnerReadDir>,
@@ -300,6 +313,7 @@ pub struct DirEntry {
     target_os = "redox",
     target_os = "nto",
     target_os = "vita",
+    target_os = "hurd",
 ))]
 struct dirent64_min {
     d_ino: u64,
@@ -321,6 +335,7 @@ struct dirent64_min {
     target_os = "redox",
     target_os = "nto",
     target_os = "vita",
+    target_os = "hurd",
 )))]
 pub struct DirEntry {
     dir: Arc<InnerReadDir>,
@@ -455,7 +470,8 @@ impl FileAttr {
         target_os = "vxworks",
         target_os = "espidf",
         target_os = "horizon",
-        target_os = "vita"
+        target_os = "vita",
+        target_os = "hurd",
     )))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         #[cfg(target_pointer_width = "32")]
@@ -473,7 +489,7 @@ impl FileAttr {
         Ok(SystemTime::new(self.stat.st_mtime as i64, 0))
     }
 
-    #[cfg(target_os = "horizon")]
+    #[cfg(any(target_os = "horizon", target_os = "hurd"))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(self.stat.st_mtim))
     }
@@ -482,7 +498,8 @@ impl FileAttr {
         target_os = "vxworks",
         target_os = "espidf",
         target_os = "horizon",
-        target_os = "vita"
+        target_os = "vita",
+        target_os = "hurd",
     )))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         #[cfg(target_pointer_width = "32")]
@@ -500,7 +517,7 @@ impl FileAttr {
         Ok(SystemTime::new(self.stat.st_atime as i64, 0))
     }
 
-    #[cfg(target_os = "horizon")]
+    #[cfg(any(target_os = "horizon", target_os = "hurd"))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(self.stat.st_atim))
     }
@@ -656,6 +673,7 @@ impl Iterator for ReadDir {
         target_os = "illumos",
         target_os = "nto",
         target_os = "vita",
+        target_os = "hurd",
     ))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         if self.end_of_stream {
@@ -756,6 +774,7 @@ impl Iterator for ReadDir {
         target_os = "illumos",
         target_os = "nto",
         target_os = "vita",
+        target_os = "hurd",
     )))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         if self.end_of_stream {
@@ -809,7 +828,12 @@ impl DirEntry {
     }
 
     #[cfg(all(
-        any(target_os = "linux", target_os = "emscripten", target_os = "android"),
+        any(
+            target_os = "linux",
+            target_os = "emscripten",
+            target_os = "android",
+            target_os = "hurd",
+        ),
         not(miri)
     ))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
@@ -833,7 +857,12 @@ impl DirEntry {
     }
 
     #[cfg(any(
-        not(any(target_os = "linux", target_os = "emscripten", target_os = "android")),
+        not(any(
+            target_os = "linux",
+            target_os = "emscripten",
+            target_os = "android",
+            target_os = "hurd",
+        )),
         miri
     ))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
@@ -892,6 +921,7 @@ impl DirEntry {
         target_os = "horizon",
         target_os = "vita",
         target_os = "nto",
+        target_os = "hurd",
     ))]
     pub fn ino(&self) -> u64 {
         self.entry.d_ino as u64
@@ -949,6 +979,7 @@ impl DirEntry {
         target_os = "redox",
         target_os = "nto",
         target_os = "vita",
+        target_os = "hurd",
     )))]
     fn name_cstr(&self) -> &CStr {
         unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
@@ -962,6 +993,7 @@ impl DirEntry {
         target_os = "redox",
         target_os = "nto",
         target_os = "vita",
+        target_os = "hurd",
     ))]
     fn name_cstr(&self) -> &CStr {
         &self.name
@@ -1131,6 +1163,7 @@ impl File {
             target_os = "netbsd",
             target_os = "openbsd",
             target_os = "nto",
+            target_os = "hurd",
         ))]
         unsafe fn os_datasync(fd: c_int) -> c_int {
             libc::fdatasync(fd)
@@ -1146,6 +1179,7 @@ impl File {
             target_os = "openbsd",
             target_os = "watchos",
             target_os = "nto",
+            target_os = "hurd",
         )))]
         unsafe fn os_datasync(fd: c_int) -> c_int {
             libc::fsync(fd)
@@ -1456,6 +1490,7 @@ impl fmt::Debug for File {
             target_os = "linux",
             target_os = "macos",
             target_os = "freebsd",
+            target_os = "hurd",
             target_os = "netbsd",
             target_os = "openbsd",
             target_os = "vxworks"
@@ -1477,6 +1512,7 @@ impl fmt::Debug for File {
             target_os = "linux",
             target_os = "macos",
             target_os = "freebsd",
+            target_os = "hurd",
             target_os = "netbsd",
             target_os = "openbsd",
             target_os = "vxworks"
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 4d17a1b0002..18acd5ecccd 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -59,9 +59,9 @@ use crate::ptr;
 use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
 use crate::sys::cvt;
 use crate::sys::weak::syscall;
-#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
+#[cfg(not(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd")))]
 use libc::sendfile as sendfile64;
-#[cfg(all(target_os = "linux", target_env = "gnu"))]
+#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd"))]
 use libc::sendfile64;
 use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
 
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 692d3ab7cc9..3edafde71e9 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -204,6 +204,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
             }
             if let Some(handler) = handler {
                 rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
+                #[cfg(target_os = "hurd")]
+                {
+                    rtassert!(signal(libc::SIGLOST, handler) != libc::SIG_ERR);
+                }
             }
         }
     }
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 48f163b6db0..f450d708dae 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -75,6 +75,7 @@ impl Socket {
                     target_os = "dragonfly",
                     target_os = "freebsd",
                     target_os = "illumos",
+                    target_os = "hurd",
                     target_os = "linux",
                     target_os = "netbsd",
                     target_os = "openbsd",
@@ -114,6 +115,7 @@ impl Socket {
                     target_os = "freebsd",
                     target_os = "illumos",
                     target_os = "linux",
+                    target_os = "hurd",
                     target_os = "netbsd",
                     target_os = "openbsd",
                     target_os = "nto",
@@ -220,6 +222,7 @@ impl Socket {
                 target_os = "freebsd",
                 target_os = "illumos",
                 target_os = "linux",
+                target_os = "hurd",
                 target_os = "netbsd",
                 target_os = "openbsd",
             ))] {
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 57e1a36dace..01ff375d215 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -46,7 +46,8 @@ extern "C" {
             target_os = "linux",
             target_os = "emscripten",
             target_os = "fuchsia",
-            target_os = "l4re"
+            target_os = "l4re",
+            target_os = "hurd",
         ),
         link_name = "__errno_location"
     )]
@@ -121,7 +122,10 @@ pub fn set_errno(e: i32) {
 pub fn error_string(errno: i32) -> String {
     extern "C" {
         #[cfg_attr(
-            all(any(target_os = "linux", target_env = "newlib"), not(target_env = "ohos")),
+            all(
+                any(target_os = "linux", target_os = "hurd", target_env = "newlib"),
+                not(target_env = "ohos")
+            ),
             link_name = "__xpg_strerror_r"
         )]
         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
@@ -359,7 +363,12 @@ pub fn current_exe() -> io::Result<PathBuf> {
     }
 }
 
-#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+#[cfg(any(
+    target_os = "linux",
+    target_os = "hurd",
+    target_os = "android",
+    target_os = "emscripten"
+))]
 pub fn current_exe() -> io::Result<PathBuf> {
     match crate::fs::read_link("/proc/self/exe") {
         Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs
index 938a46bfdd8..1239c65a483 100644
--- a/library/std/src/sys/unix/pipe.rs
+++ b/library/std/src/sys/unix/pipe.rs
@@ -21,6 +21,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
         if #[cfg(any(
             target_os = "dragonfly",
             target_os = "freebsd",
+            target_os = "hurd",
             target_os = "linux",
             target_os = "netbsd",
             target_os = "openbsd",
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index f729da44774..1ca11a7f9d7 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -586,6 +586,23 @@ impl fmt::Debug for Command {
             if let Some(ref cwd) = self.cwd {
                 write!(f, "cd {cwd:?} && ")?;
             }
+            if self.env.does_clear() {
+                write!(f, "env -i ")?;
+                // Altered env vars will be printed next, that should exactly work as expected.
+            } else {
+                // Removed env vars need the command to be wrapped in `env`.
+                let mut any_removed = false;
+                for (key, value_opt) in self.get_envs() {
+                    if value_opt.is_none() {
+                        if !any_removed {
+                            write!(f, "env ")?;
+                            any_removed = true;
+                        }
+                        write!(f, "-u {} ", key.to_string_lossy())?;
+                    }
+                }
+            }
+            // Altered env vars can just be added in front of the program.
             for (key, value_opt) in self.get_envs() {
                 if let Some(value) = value_opt {
                     write!(f, "{}={value:?} ", key.to_string_lossy())?;
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 75b54064501..564f8c48290 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -374,6 +374,13 @@ impl Command {
                         return Err(io::Error::last_os_error());
                     }
                 }
+                #[cfg(target_os = "hurd")]
+                {
+                    let ret = sys::signal(libc::SIGLOST, libc::SIG_DFL);
+                    if ret == libc::SIG_ERR {
+                        return Err(io::Error::last_os_error());
+                    }
+                }
             }
         }
 
@@ -620,6 +627,10 @@ impl Command {
                 let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
                 cvt(sigemptyset(default_set.as_mut_ptr()))?;
                 cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
+                #[cfg(target_os = "hurd")]
+                {
+                    cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGLOST))?;
+                }
                 cvt_nz(libc::posix_spawnattr_setsigdefault(
                     attrs.0.as_mut_ptr(),
                     default_set.as_ptr(),
@@ -993,6 +1004,8 @@ fn signal_string(signal: i32) -> &'static str {
             target_os = "dragonfly"
         ))]
         libc::SIGINFO => " (SIGINFO)",
+        #[cfg(target_os = "hurd")]
+        libc::SIGLOST => " (SIGLOST)",
         _ => "",
     }
 }
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs
index b59d4ba26af..73c530786b2 100644
--- a/library/std/src/sys/unix/stack_overflow.rs
+++ b/library/std/src/sys/unix/stack_overflow.rs
@@ -32,6 +32,7 @@ impl Drop for Handler {
     target_os = "macos",
     target_os = "dragonfly",
     target_os = "freebsd",
+    target_os = "hurd",
     target_os = "solaris",
     target_os = "illumos",
     target_os = "netbsd",
@@ -193,6 +194,7 @@ mod imp {
     target_os = "macos",
     target_os = "dragonfly",
     target_os = "freebsd",
+    target_os = "hurd",
     target_os = "solaris",
     target_os = "illumos",
     target_os = "netbsd",
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 2afec897a88..311ed95022f 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -216,7 +216,8 @@ impl Thread {
         target_os = "l4re",
         target_os = "emscripten",
         target_os = "redox",
-        target_os = "vxworks"
+        target_os = "vxworks",
+        target_os = "hurd",
     ))]
     pub fn set_name(_name: &CStr) {
         // Newlib, Emscripten, and VxWorks have no way to set a thread name.
@@ -309,6 +310,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
             target_os = "android",
             target_os = "emscripten",
             target_os = "fuchsia",
+            target_os = "hurd",
             target_os = "ios",
             target_os = "tvos",
             target_os = "linux",
@@ -316,25 +318,38 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
             target_os = "solaris",
             target_os = "illumos",
         ))] {
+            #[allow(unused_assignments)]
+            #[allow(unused_mut)]
+            let mut quota = usize::MAX;
+
             #[cfg(any(target_os = "android", target_os = "linux"))]
             {
-                let quota = cgroups::quota().max(1);
+                quota = cgroups::quota().max(1);
                 let mut set: libc::cpu_set_t = unsafe { mem::zeroed() };
                 unsafe {
                     if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 {
                         let count = libc::CPU_COUNT(&set) as usize;
                         let count = count.min(quota);
-                        // reported to occur on MIPS kernels older than our minimum supported kernel version for those targets
-                        let count = NonZeroUsize::new(count)
-                            .expect("CPU count must be > 0. This may be a bug in sched_getaffinity(); try upgrading the kernel.");
-                        return Ok(count);
+
+                        // According to sched_getaffinity's API it should always be non-zero, but
+                        // some old MIPS kernels were buggy and zero-initialized the mask if
+                        // none was explicitly set.
+                        // In that case we use the sysconf fallback.
+                        if let Some(count) = NonZeroUsize::new(count) {
+                            return Ok(count)
+                        }
                     }
                 }
             }
             match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
                 -1 => Err(io::Error::last_os_error()),
                 0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
-                cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
+                cpus => {
+                    let count = cpus as usize;
+                    // Cover the unusual situation where we were able to get the quota but not the affinity mask
+                    let count = count.min(quota);
+                    Ok(unsafe { NonZeroUsize::new_unchecked(count) })
+                }
             }
         } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
             use crate::ptr;
@@ -692,6 +707,7 @@ mod cgroups {
 #[cfg(all(
     not(target_os = "linux"),
     not(target_os = "freebsd"),
+    not(target_os = "hurd"),
     not(target_os = "macos"),
     not(target_os = "netbsd"),
     not(target_os = "openbsd"),
@@ -712,6 +728,7 @@ pub mod guard {
 #[cfg(any(
     target_os = "linux",
     target_os = "freebsd",
+    target_os = "hurd",
     target_os = "macos",
     target_os = "netbsd",
     target_os = "openbsd",
@@ -768,6 +785,7 @@ pub mod guard {
     #[cfg(any(
         target_os = "android",
         target_os = "freebsd",
+        target_os = "hurd",
         target_os = "linux",
         target_os = "netbsd",
         target_os = "l4re"
@@ -905,6 +923,7 @@ pub mod guard {
     #[cfg(any(
         target_os = "android",
         target_os = "freebsd",
+        target_os = "hurd",
         target_os = "linux",
         target_os = "netbsd",
         target_os = "l4re"
@@ -936,7 +955,7 @@ pub mod guard {
             assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
 
             let stackaddr = stackptr.addr();
-            ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd")) {
+            ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) {
                 Some(stackaddr - guardsize..stackaddr)
             } else if cfg!(all(target_os = "linux", target_env = "musl")) {
                 Some(stackaddr - guardsize..stackaddr)
diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs
index 236d2f2ee29..1da41d4b4bf 100644
--- a/library/std/src/sys/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/unix/thread_local_dtor.rs
@@ -11,7 +11,7 @@
 // Note, however, that we run on lots older linuxes, as well as cross
 // compiling from a newer linux to an older linux, so we also have a
 // fallback implementation to use as well.
-#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd"))]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::mem;
     use crate::sys_common::thread_local_dtor::register_dtor_fallback;
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 17b4130c202..4fe61b28488 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -35,7 +35,7 @@ pub(in crate::sys::unix) struct Timespec {
 }
 
 impl SystemTime {
-    #[cfg_attr(target_os = "horizon", allow(unused))]
+    #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
     pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
         SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
     }
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 2976a9f578e..4f5b17deaa2 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -32,6 +32,7 @@ cfg_if::cfg_if! {
 cfg_if::cfg_if! {
     if #[cfg(any(
         target_os = "linux", target_os = "android",
+        target_os = "hurd",
         target_os = "dragonfly", target_os = "freebsd",
         target_os = "openbsd", target_os = "netbsd",
         target_os = "haiku", target_os = "nto"))] {
diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs
index 18883048dae..4d295cf0f09 100644
--- a/library/std/src/sys_common/process.rs
+++ b/library/std/src/sys_common/process.rs
@@ -80,6 +80,10 @@ impl CommandEnv {
         self.vars.clear();
     }
 
+    pub fn does_clear(&self) -> bool {
+        self.clear
+    }
+
     pub fn have_changed_path(&self) -> bool {
         self.saw_path || self.clear
     }
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 62e97c65569..df4f286a526 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -148,3 +148,7 @@ extern "C" {}
 #[cfg(target_os = "nto")]
 #[link(name = "gcc_s")]
 extern "C" {}
+
+#[cfg(target_os = "hurd")]
+#[link(name = "gcc_s")]
+extern "C" {}
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index a9aa7524e8b..d58f0d54d3a 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -265,7 +265,8 @@ def default_build_triple(verbose):
         'FreeBSD': 'unknown-freebsd',
         'Haiku': 'unknown-haiku',
         'NetBSD': 'unknown-netbsd',
-        'OpenBSD': 'unknown-openbsd'
+        'OpenBSD': 'unknown-openbsd',
+        'GNU': 'unknown-hurd',
     }
 
     # Consider the direct transformation first and then the special cases
@@ -336,6 +337,7 @@ def default_build_triple(verbose):
         'i386': 'i686',
         'i486': 'i686',
         'i686': 'i686',
+        'i686-AT386': 'i686',
         'i786': 'i686',
         'loongarch64': 'loongarch64',
         'm68k': 'm68k',
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 1e001fae8ab..8b8d4b23795 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -133,7 +133,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     // #[cfg(bootstrap)]
     (Some(Mode::Std), "target_vendor", Some(&["unikraft"])),
     (Some(Mode::Std), "target_env", Some(&["libnx"])),
-    (Some(Mode::Std), "target_os", Some(&["teeos"])),
+    // #[cfg(bootstrap)] hurd
+    (Some(Mode::Std), "target_os", Some(&["teeos", "hurd"])),
+    (Some(Mode::Rustc), "target_os", Some(&["hurd"])),
     // #[cfg(bootstrap)] mips32r6, mips64r6
     (
         Some(Mode::Std),
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 94605e2a217..5c663386446 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -28,6 +28,7 @@
     - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [\*-android and \*-androideabi](platform-support/android.md)
     - [\*-linux-ohos](platform-support/openharmony.md)
+    - [\*-hurd-gnu](platform-support/hurd.md)
     - [aarch64-unknown-teeos](platform-support/aarch64-unknown-teeos.md)
     - [\*-esp-espidf](platform-support/esp-idf.md)
     - [\*-unknown-fuchsia](platform-support/fuchsia.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 70b35526ee5..7c0c56035c0 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -269,6 +269,7 @@ target | std | host | notes
 `i686-pc-windows-msvc` | * |  | 32-bit Windows XP support
 [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
+[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd
 [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
 `i686-uwp-windows-gnu` | ? |  |
diff --git a/src/doc/rustc/src/platform-support/hurd.md b/src/doc/rustc/src/platform-support/hurd.md
new file mode 100644
index 00000000000..ddf40213ed4
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/hurd.md
@@ -0,0 +1,35 @@
+# `i686-unknown-hurd-gnu`
+
+**Tier: 3**
+
+[GNU/Hurd] is the GNU Hurd is the GNU project's replacement for the Unix kernel.
+
+## Target maintainers
+
+- Samuel Thibault, `samuel.thibault@ens-lyon.org`, https://github.com/sthibaul/
+
+## Requirements
+
+The target supports host tools.
+
+The GNU/Hurd target supports `std` and uses the standard ELF file format.
+
+## Building the target
+
+This target can be built by adding `i686-unknown-hurd-gnu` as target in the rustc list.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Tests can be run in the same way as a regular binary.
+
+## Cross-compilation toolchains and C code
+
+The target supports C code, the GNU toolchain calls the target
+`i686-unknown-gnu`.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 190b1b038b6..c4011461885 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -793,6 +793,7 @@ fn clean_ty_generics<'tcx>(
                 }
                 Some(clean_generic_param_def(param, cx))
             }
+            ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None,
             ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
         })
         .collect::<ThinVec<GenericParamDef>>();
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index ef7794cc41e..b665f684167 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -31,7 +31,7 @@ use rustc_resolve::rustdoc::{
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{self, FileName, Loc};
+use rustc_span::{self, FileName, Loc, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
 
@@ -622,7 +622,7 @@ impl Item {
         fn build_fn_header(
             def_id: DefId,
             tcx: TyCtxt<'_>,
-            asyncness: hir::IsAsync,
+            asyncness: ty::Asyncness,
         ) -> hir::FnHeader {
             let sig = tcx.fn_sig(def_id).skip_binder();
             let constness =
@@ -631,6 +631,10 @@ impl Item {
                 } else {
                     hir::Constness::NotConst
                 };
+            let asyncness = match asyncness {
+                ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
+                ty::Asyncness::No => hir::IsAsync::NotAsync,
+            };
             hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }
         }
         let header = match *self.kind {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index e680b451421..8388f722a7f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -283,7 +283,7 @@ pub(crate) fn print_evaluated_const(
             (_, &ty::Ref(..)) => None,
             (mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
             (mir::ConstValue::Scalar(_), _) => {
-                let const_ = mir::ConstantKind::from_value(val, ty);
+                let const_ = mir::Const::from_value(val, ty);
                 Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
             }
             _ => None,
@@ -319,20 +319,20 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
 
 fn print_const_with_custom_print_scalar<'tcx>(
     tcx: TyCtxt<'tcx>,
-    ct: mir::ConstantKind<'tcx>,
+    ct: mir::Const<'tcx>,
     underscores_and_type: bool,
 ) -> String {
     // Use a slightly different format for integer types which always shows the actual value.
     // For all other types, fallback to the original `pretty_print_const`.
     match (ct, ct.ty().kind()) {
-        (mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
+        (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
             if underscores_and_type {
                 format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
             } else {
                 int.to_string()
             }
         }
-        (mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => {
+        (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => {
             let ty = ct.ty();
             let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
             let data = int.assert_bits(size);
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 2f611c31a07..170e559e698 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1599,7 +1599,7 @@ impl PrintWithSpace for hir::Unsafety {
 impl PrintWithSpace for hir::IsAsync {
     fn print_with_space(&self) -> &str {
         match self {
-            hir::IsAsync::Async => "async ",
+            hir::IsAsync::Async(_) => "async ",
             hir::IsAsync::NotAsync => "",
         }
     }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 2f88f6dc6e0..fc2acb6eaa3 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -503,13 +503,6 @@ fn opts() -> Vec<RustcOptGroup> {
                 "PATH",
             )
         }),
-        unstable("disable-per-crate-search", |o| {
-            o.optflagmulti(
-                "",
-                "disable-per-crate-search",
-                "disables generating the crate selector on the search box",
-            )
-        }),
         unstable("persist-doctests", |o| {
             o.optopt(
                 "",
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 96c5c7fc509..3f60e5a7c4d 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
                         .tcx
                         .const_eval_poly(def_id.to_def_id())
                         .ok()
-                        .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty));
+                        .map(|val| rustc_middle::mir::Const::from_value(val, ty));
                     if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
                         if let ty::Adt(adt, _) = ty.kind() {
                             if adt.is_enum() {
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 6e13148f2fc..7c0485914b8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                         Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
                         None => {
                             let min_val_const = ty.numeric_min_val(cx.tcx)?;
-                            miri_to_const(cx, mir::ConstantKind::from_ty_const(min_val_const, cx.tcx))?
+                            miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
                         },
                     };
                     let rhs_const = match rhs {
                         Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
                         None => {
                             let max_val_const = ty.numeric_max_val(cx.tcx)?;
-                            miri_to_const(cx, mir::ConstantKind::from_ty_const(max_val_const, cx.tcx))?
+                            miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
                         },
                     };
                     let lhs_val = lhs_const.int_value(cx, ty)?;
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 8072aded851..a10aa65e594 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -315,7 +315,7 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
         let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
 
         let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
-        if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
+        if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind {
             let body_span = cx.tcx.hir().span_with_body(body_owner);
             if let Some(span) = self.const_span && span.contains(body_span) {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index 102845ceed0..80389cbf84b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -72,7 +72,7 @@ impl Context {
         let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
 
         match cx.tcx.hir().body_owner_kind(body_owner_def_id) {
-            hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
+            hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const { .. } => {
                 let body_span = cx.tcx.hir().span_with_body(body_owner);
 
                 if let Some(span) = self.const_span {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index fc49b58e0a7..f42836611ca 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -10,6 +10,7 @@ use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -84,7 +85,7 @@ fn find_innermost_closure<'tcx>(
     cx: &LateContext<'tcx>,
     mut expr: &'tcx hir::Expr<'tcx>,
     mut steps: usize,
-) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, hir::IsAsync)> {
+) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, ty::Asyncness)> {
     let mut data = None;
 
     while let hir::ExprKind::Closure(closure) = expr.kind
@@ -98,9 +99,9 @@ fn find_innermost_closure<'tcx>(
     {
         expr = body.value;
         data = Some((body.value, closure.fn_decl, if is_async_closure(body) {
-            hir::IsAsync::Async
+            ty::Asyncness::Yes
         } else {
-            hir::IsAsync::NotAsync
+            ty::Asyncness::No
         }));
         steps -= 1;
     }
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index c88fce22f7f..a136de86240 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -21,7 +21,7 @@ use std::iter;
 /// A `LitKind`-like enum to fold constant `Expr`s into.
 #[derive(Debug, Clone)]
 pub enum Constant<'tcx> {
-    Adt(rustc_middle::mir::ConstantKind<'tcx>),
+    Adt(rustc_middle::mir::Const<'tcx>),
     /// A `String` (e.g., "abc").
     Str(String),
     /// A binary string (e.g., `b"abc"`).
@@ -482,7 +482,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     .tcx
                     .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
                     .ok()
-                    .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
+                    .map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
                 let result = miri_to_const(self.lcx, result)?;
                 self.source = ConstantSource::Constant;
                 Some(result)
@@ -655,10 +655,10 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     }
 }
 
-pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant<'tcx>> {
+pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
     use rustc_middle::mir::ConstValue;
     match result {
-        mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
+        mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
             ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
             ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
             ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
@@ -671,11 +671,11 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
             ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
             _ => None,
         },
-        mir::ConstantKind::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => {
+        mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => {
             let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
             String::from_utf8(data.to_owned()).ok().map(Constant::Str)
         }
-        mir::ConstantKind::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
+        mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
             let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
             match result.ty().kind() {
                 ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
@@ -714,17 +714,17 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
 fn field_of_struct<'tcx>(
     adt_def: ty::AdtDef<'tcx>,
     lcx: &LateContext<'tcx>,
-    result: mir::ConstantKind<'tcx>,
+    result: mir::Const<'tcx>,
     field: &Ident,
-) -> Option<mir::ConstantKind<'tcx>> {
-    if let mir::ConstantKind::Val(result, ty) = result
+) -> Option<mir::Const<'tcx>> {
+    if let mir::Const::Val(result, ty) = result
         && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty))
         && let Some(dc_variant) = dc.variant
         && let Some(variant) = adt_def.variants().get(dc_variant)
         && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
         && let Some(&(val, ty)) = dc.fields.get(field_idx)
     {
-        Some(mir::ConstantKind::Val(val, ty))
+        Some(mir::Const::Val(val, ty))
     }
     else {
         None
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 4ef3ec19647..be1c46319c2 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -90,14 +90,14 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
-    ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item,
+    ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
     ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
     QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
-use rustc_middle::mir::ConstantKind;
+use rustc_middle::mir::Const;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::fast_reject::SimplifiedType;
@@ -1510,7 +1510,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
                 && let bnd_ty = subst.type_at(0)
                 && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
                 && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
-                && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty)
+                && let min_const_kind = Const::from_value(const_val, bnd_ty)
                 && let Some(min_const) = miri_to_const(cx, min_const_kind)
                 && let Some(start_const) = constant(cx, cx.typeck_results(), start)
             {
@@ -1526,7 +1526,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
                         && let bnd_ty = subst.type_at(0)
                         && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
                         && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
-                        && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty)
+                        && let max_const_kind = Const::from_value(const_val, bnd_ty)
                         && let Some(max_const) = miri_to_const(cx, max_const_kind)
                         && let Some(end_const) = constant(cx, cx.typeck_results(), end)
                     {
@@ -1958,8 +1958,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
 /// Checks if the given function kind is an async function.
 pub fn is_async_fn(kind: FnKind<'_>) -> bool {
     match kind {
-        FnKind::ItemFn(_, _, header) => header.asyncness == IsAsync::Async,
-        FnKind::Method(_, sig) => sig.header.asyncness == IsAsync::Async,
+        FnKind::ItemFn(_, _, header) => header.asyncness .is_async(),
+        FnKind::Method(_, sig) => sig.header.asyncness.is_async(),
         FnKind::Closure => false,
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index dc7756533ac..4b06b12fb94 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -207,7 +207,8 @@ fn path_segment_certainty(
             // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE.
             if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
                 let generics = cx.tcx.generics_of(def_id);
-                let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && generics.params.is_empty()
+                let count = generics.params.len() - generics.host_effect_index.is_some() as usize;
+                let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0
                 {
                     Certainty::Certain(None)
                 } else {
@@ -299,7 +300,7 @@ fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> b
 
     // Check that all type parameters appear in the functions input types.
     (0..(generics.parent_count + generics.params.len()) as u32).all(|index| {
-        fn_sig
+        Some(index as usize) == generics.host_effect_index || fn_sig
             .inputs()
             .iter()
             .any(|input_ty| contains_param(*input_ty.skip_binder(), index))
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 073b8b6a661..24b9fa0776f 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -516,8 +516,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
 
         // Atomics wrap around on overflow.
-        let val = this.binary_op(op, &old, rhs)?;
-        let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val };
+        let val = this.wrapping_binary_op(op, &old, rhs)?;
+        let val = if neg { this.wrapping_unary_op(mir::UnOp::Not, &val)? } else { val };
         this.allow_data_races_mut(|this| this.write_immediate(*val, place))?;
 
         this.validate_atomic_rmw(place, atomic)?;
@@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
 
         this.validate_overlapping_atomic(place)?;
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
-        let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
+        let lt = this.wrapping_binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
 
         let new_val = if min {
             if lt { &old } else { &rhs }
@@ -605,7 +605,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         // Read as immediate for the sake of `binary_op()`
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
         // `binary_op` will bail if either of them is not a scalar.
-        let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?;
+        let eq = this.wrapping_binary_op(mir::BinOp::Eq, &old, expect_old)?;
         // If the operation would succeed, but is "weak", fail some portion
         // of the time, based on `success_rate`.
         let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate;
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index b05087134a0..537c767065d 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1013,15 +1013,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     fn float_to_int_checked<F>(
         &self,
         f: F,
-        dest_ty: Ty<'tcx>,
+        cast_to: TyAndLayout<'tcx>,
         round: rustc_apfloat::Round,
-    ) -> Option<Scalar<Provenance>>
+    ) -> Option<ImmTy<'tcx, Provenance>>
     where
         F: rustc_apfloat::Float + Into<Scalar<Provenance>>,
     {
         let this = self.eval_context_ref();
 
-        match dest_ty.kind() {
+        let val = match cast_to.ty.kind() {
             // Unsigned
             ty::Uint(t) => {
                 let size = Integer::from_uint_ty(this, *t).size();
@@ -1033,11 +1033,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 ) {
                     // Floating point value is NaN (flagged with INVALID_OP) or outside the range
                     // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
-                    None
+                    return None
                 } else {
                     // Floating point value can be represented by the integer type after rounding.
                     // The INEXACT flag is ignored on purpose to allow rounding.
-                    Some(Scalar::from_uint(res.value, size))
+                    Scalar::from_uint(res.value, size)
                 }
             }
             // Signed
@@ -1051,20 +1051,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 ) {
                     // Floating point value is NaN (flagged with INVALID_OP) or outside the range
                     // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
-                    None
+                    return None
                 } else {
                     // Floating point value can be represented by the integer type after rounding.
                     // The INEXACT flag is ignored on purpose to allow rounding.
-                    Some(Scalar::from_int(res.value, size))
+                    Scalar::from_int(res.value, size)
                 }
             }
             // Nothing else
             _ =>
                 span_bug!(
                     this.cur_span(),
-                    "attempted float-to-int conversion with non-int output type {dest_ty:?}"
+                    "attempted float-to-int conversion with non-int output type {}",
+                    cast_to.ty,
                 ),
-        }
+        };
+        Some(ImmTy::from_scalar(val, cast_to))
     }
 
     /// Returns an integer type that is twice wide as `ty`
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index ce7f47b5b4f..f1c50794ca8 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -998,7 +998,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, Provenance>,
         right: &ImmTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> {
         ecx.binary_ptr_op(bin_op, left, right)
     }
 
diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs
index 368aa2bacdc..27fe7374ea5 100644
--- a/src/tools/miri/src/operator.rs
+++ b/src/tools/miri/src/operator.rs
@@ -1,6 +1,6 @@
 use log::trace;
 
-use rustc_middle::{mir, ty::Ty};
+use rustc_middle::mir;
 use rustc_target::abi::Size;
 
 use crate::*;
@@ -11,7 +11,7 @@ pub trait EvalContextExt<'tcx> {
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, Provenance>,
         right: &ImmTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)>;
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)>;
 }
 
 impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
@@ -20,7 +20,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, Provenance>,
         right: &ImmTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> {
         use rustc_middle::mir::BinOp::*;
 
         trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);
@@ -50,7 +50,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
                     Ge => left >= right,
                     _ => bug!(),
                 };
-                (Scalar::from_bool(res), false, self.tcx.types.bool)
+                (ImmTy::from_bool(res, *self.tcx), false)
             }
 
             // Some more operations are possible with atomics.
@@ -65,12 +65,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
                     right.to_scalar().to_target_usize(self)?,
                     self.machine.layouts.usize,
                 );
-                let (result, overflowing, _ty) =
+                let (result, overflowing) =
                     self.overflowing_binary_op(bin_op, &left, &right)?;
                 // Construct a new pointer with the provenance of `ptr` (the LHS).
                 let result_ptr =
-                    Pointer::new(ptr.provenance, Size::from_bytes(result.to_target_usize(self)?));
-                (Scalar::from_maybe_pointer(result_ptr, self), overflowing, left.layout.ty)
+                    Pointer::new(ptr.provenance, Size::from_bytes(result.to_scalar().to_target_usize(self)?));
+                (ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout), overflowing)
             }
 
             _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs
index ef9d0710448..d54145dbdc7 100644
--- a/src/tools/miri/src/shims/intrinsics/mod.rs
+++ b/src/tools/miri/src/shims/intrinsics/mod.rs
@@ -89,10 +89,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [left, right] = check_arg_count(args)?;
                 let left = this.read_immediate(left)?;
                 let right = this.read_immediate(right)?;
-                let (val, _overflowed, _ty) =
-                    this.overflowing_binary_op(mir::BinOp::Eq, &left, &right)?;
+                let val = this.wrapping_binary_op(mir::BinOp::Eq, &left, &right)?;
                 // We're type punning a bool as an u8 here.
-                this.write_scalar(val, dest)?;
+                this.write_scalar(val.to_scalar(), dest)?;
             }
             "const_allocate" => {
                 // For now, for compatibility with the run-time implementation of this, we just return null.
@@ -369,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     ty::Float(FloatTy::F32) => {
                         let f = val.to_scalar().to_f32()?;
                         this
-                            .float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
+                            .float_to_int_checked(f, dest.layout, Round::TowardZero)
                             .ok_or_else(|| {
                                 err_ub_format!(
                                     "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -380,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     ty::Float(FloatTy::F64) => {
                         let f = val.to_scalar().to_f64()?;
                         this
-                            .float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
+                            .float_to_int_checked(f, dest.layout, Round::TowardZero)
                             .ok_or_else(|| {
                                 err_ub_format!(
                                     "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -396,7 +395,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                         ),
                 };
 
-                this.write_scalar(res, dest)?;
+                this.write_immediate(*res, dest)?;
             }
 
             // Other
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index 626ead378e7..49ba7e5556e 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let op = this.read_immediate(&this.project_index(&op, i)?)?;
                     let dest = this.project_index(&dest, i)?;
                     let val = match which {
-                        Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(),
+                        Op::MirOp(mir_op) => this.wrapping_unary_op(mir_op, &op)?.to_scalar(),
                         Op::Abs => {
                             // Works for f32 and f64.
                             let ty::Float(float_ty) = op.layout.ty.kind() else {
@@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let dest = this.project_index(&dest, i)?;
                     let val = match which {
                         Op::MirOp(mir_op) => {
-                            let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?;
+                            let (val, overflowed) = this.overflowing_binary_op(mir_op, &left, &right)?;
                             if matches!(mir_op, BinOp::Shl | BinOp::Shr) {
                                 // Shifts have extra UB as SIMD operations that the MIR binop does not have.
                                 // See <https://github.com/rust-lang/rust/issues/91237>.
@@ -188,13 +188,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                             }
                             if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) {
                                 // Special handling for boolean-returning operations
-                                assert_eq!(ty, this.tcx.types.bool);
-                                let val = val.to_bool().unwrap();
+                                assert_eq!(val.layout.ty, this.tcx.types.bool);
+                                let val = val.to_scalar().to_bool().unwrap();
                                 bool_to_simd_element(val, dest.layout.size)
                             } else {
-                                assert_ne!(ty, this.tcx.types.bool);
-                                assert_eq!(ty, dest.layout.ty);
-                                val
+                                assert_ne!(val.layout.ty, this.tcx.types.bool);
+                                assert_eq!(val.layout.ty, dest.layout.ty);
+                                val.to_scalar()
                             }
                         }
                         Op::SaturatingOp(mir_op) => {
@@ -304,18 +304,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let op = this.read_immediate(&this.project_index(&op, i)?)?;
                     res = match which {
                         Op::MirOp(mir_op) => {
-                            this.binary_op(mir_op, &res, &op)?
+                            this.wrapping_binary_op(mir_op, &res, &op)?
                         }
                         Op::MirOpBool(mir_op) => {
                             let op = imm_from_bool(simd_element_to_bool(op)?);
-                            this.binary_op(mir_op, &res, &op)?
+                            this.wrapping_binary_op(mir_op, &res, &op)?
                         }
                         Op::Max => {
                             if matches!(res.layout.ty.kind(), ty::Float(_)) {
                                 ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout)
                             } else {
                                 // Just boring integers, so NaNs to worry about
-                                if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? {
+                                if this.wrapping_binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? {
                                     res
                                 } else {
                                     op
@@ -327,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                                 ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout)
                             } else {
                                 // Just boring integers, so NaNs to worry about
-                                if this.binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? {
+                                if this.wrapping_binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? {
                                     res
                                 } else {
                                     op
@@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let mut res = init;
                 for i in 0..op_len {
                     let op = this.read_immediate(&this.project_index(&op, i)?)?;
-                    res = this.binary_op(mir_op, &res, &op)?;
+                    res = this.wrapping_binary_op(mir_op, &res, &op)?;
                 }
                 this.write_immediate(*res, dest)?;
             }
@@ -441,17 +441,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                         // Int-to-(int|float): always safe
                         (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_))
                             if safe_cast || unsafe_cast =>
-                            this.int_to_int_or_float(&op, dest.layout.ty)?,
+                            this.int_to_int_or_float(&op, dest.layout)?,
                         // Float-to-float: always safe
                         (ty::Float(_), ty::Float(_)) if safe_cast || unsafe_cast =>
-                            this.float_to_float_or_int(&op, dest.layout.ty)?,
+                            this.float_to_float_or_int(&op, dest.layout)?,
                         // Float-to-int in safe mode
                         (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
-                            this.float_to_float_or_int(&op, dest.layout.ty)?,
+                            this.float_to_float_or_int(&op, dest.layout)?,
                         // Float-to-int in unchecked mode
                         (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
                             let f = op.to_scalar().to_f32()?;
-                            this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
+                            this.float_to_int_checked(f, dest.layout, Round::TowardZero)
                                 .ok_or_else(|| {
                                     err_ub_format!(
                                         "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                         }
                         (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
                             let f = op.to_scalar().to_f64()?;
-                            this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
+                            this.float_to_int_checked(f, dest.layout, Round::TowardZero)
                                 .ok_or_else(|| {
                                     err_ub_format!(
                                         "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -473,12 +473,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                         }
                         // Ptr-to-ptr cast
                         (ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast =>
-                            this.ptr_to_ptr(&op, dest.layout.ty)?,
+                            this.ptr_to_ptr(&op, dest.layout)?,
                         // Ptr/Int casts
                         (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast =>
-                            this.pointer_expose_address_cast(&op, dest.layout.ty)?,
+                            this.pointer_expose_address_cast(&op, dest.layout)?,
                         (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
-                            this.pointer_from_exposed_address_cast(&op, dest.layout.ty)?,
+                            this.pointer_from_exposed_address_cast(&op, dest.layout)?,
                         // Error otherwise
                         _ =>
                             throw_unsup_format!(
@@ -487,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                                 to_ty = dest.layout.ty,
                             ),
                     };
-                    this.write_immediate(val, &dest)?;
+                    this.write_immediate(*val, &dest)?;
                 }
             }
             "shuffle" => {
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index ccc729aae1a..cbdc500be78 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -80,8 +80,8 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
 ) -> InterpResult<'tcx, Scalar<Provenance>> {
     match which {
         FloatBinOp::Arith(which) => {
-            let (res, _overflow, _ty) = this.overflowing_binary_op(which, left, right)?;
-            Ok(res)
+            let res = this.wrapping_binary_op(which, left, right)?;
+            Ok(res.to_scalar())
         }
         FloatBinOp::Cmp(which) => {
             let left = left.to_scalar().to_float::<F>()?;
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index 30ad088206a..b6b994b45ac 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -173,12 +173,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
                     // Fallback to minimum acording to SSE semantics.
-                    Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size)
+                    ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
                 });
 
-                this.write_scalar(res, dest)?;
+                this.write_immediate(*res, dest)?;
             }
             // Used to implement the _mm_cvtsi32_ss and _mm_cvtsi64_ss functions.
             // Converts `right` from i32/i64 to f32. Returns a SIMD vector with
@@ -196,8 +196,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 let right = this.read_immediate(right)?;
                 let dest0 = this.project_index(&dest, 0)?;
-                let res0 = this.int_to_int_or_float(&right, dest0.layout.ty)?;
-                this.write_immediate(res0, &dest0)?;
+                let res0 = this.int_to_int_or_float(&right, dest0.layout)?;
+                this.write_immediate(*res0, &dest0)?;
 
                 for i in 1..dest_len {
                     this.copy_op(
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index b68690a835c..7e10d1d3726 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -56,36 +56,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let dest = this.project_index(&dest, i)?;
 
                     // Widen the operands to avoid overflow
-                    let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty);
-                    let twice_wide_layout = this.layout_of(twice_wide_ty)?;
-                    let left = this.int_to_int_or_float(&left, twice_wide_ty)?;
-                    let right = this.int_to_int_or_float(&right, twice_wide_ty)?;
+                    let twice_wide = this.layout_of(this.get_twice_wide_int_ty(left.layout.ty))?;
+                    let left = this.int_to_int_or_float(&left, twice_wide)?;
+                    let right = this.int_to_int_or_float(&right, twice_wide)?;
 
                     // Calculate left + right + 1
-                    let (added, _overflow, _ty) = this.overflowing_binary_op(
+                    let added = this.wrapping_binary_op(
                         mir::BinOp::Add,
-                        &ImmTy::from_immediate(left, twice_wide_layout),
-                        &ImmTy::from_immediate(right, twice_wide_layout),
+                        &left,
+                        &right,
                     )?;
-                    let (added, _overflow, _ty) = this.overflowing_binary_op(
+                    let added = this.wrapping_binary_op(
                         mir::BinOp::Add,
-                        &ImmTy::from_scalar(added, twice_wide_layout),
-                        &ImmTy::from_uint(1u32, twice_wide_layout),
+                        &added,
+                        &ImmTy::from_uint(1u32, twice_wide),
                     )?;
 
                     // Calculate (left + right + 1) / 2
-                    let (divided, _overflow, _ty) = this.overflowing_binary_op(
+                    let divided = this.wrapping_binary_op(
                         mir::BinOp::Div,
-                        &ImmTy::from_scalar(added, twice_wide_layout),
-                        &ImmTy::from_uint(2u32, twice_wide_layout),
+                        &added,
+                        &ImmTy::from_uint(2u32, twice_wide),
                     )?;
 
                     // Narrow back to the original type
                     let res = this.int_to_int_or_float(
-                        &ImmTy::from_scalar(divided, twice_wide_layout),
-                        dest.layout.ty,
+                        &divided,
+                        dest.layout,
                     )?;
-                    this.write_immediate(res, &dest)?;
+                    this.write_immediate(*res, &dest)?;
                 }
             }
             // Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions.
@@ -106,30 +105,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let dest = this.project_index(&dest, i)?;
 
                     // Widen the operands to avoid overflow
-                    let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty);
-                    let twice_wide_layout = this.layout_of(twice_wide_ty)?;
-                    let left = this.int_to_int_or_float(&left, twice_wide_ty)?;
-                    let right = this.int_to_int_or_float(&right, twice_wide_ty)?;
+                    let twice_wide = this.layout_of(this.get_twice_wide_int_ty(left.layout.ty))?;
+                    let left = this.int_to_int_or_float(&left, twice_wide)?;
+                    let right = this.int_to_int_or_float(&right, twice_wide)?;
 
                     // Multiply
-                    let (multiplied, _overflow, _ty) = this.overflowing_binary_op(
+                    let multiplied = this.wrapping_binary_op(
                         mir::BinOp::Mul,
-                        &ImmTy::from_immediate(left, twice_wide_layout),
-                        &ImmTy::from_immediate(right, twice_wide_layout),
+                        &left,
+                        &right,
                     )?;
                     // Keep the high half
-                    let (high, _overflow, _ty) = this.overflowing_binary_op(
+                    let high = this.wrapping_binary_op(
                         mir::BinOp::Shr,
-                        &ImmTy::from_scalar(multiplied, twice_wide_layout),
-                        &ImmTy::from_uint(dest.layout.size.bits(), twice_wide_layout),
+                        &multiplied,
+                        &ImmTy::from_uint(dest.layout.size.bits(), twice_wide),
                     )?;
 
                     // Narrow back to the original type
                     let res = this.int_to_int_or_float(
-                        &ImmTy::from_scalar(high, twice_wide_layout),
-                        dest.layout.ty,
+                        &high,
+                        dest.layout,
                     )?;
-                    this.write_immediate(res, &dest)?;
+                    this.write_immediate(*res, &dest)?;
                 }
             }
             // Used to implement the _mm_mul_epu32 function.
@@ -392,11 +390,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let dest = this.project_index(&dest, i)?;
 
                     let res =
-                        this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                        this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
                             // Fallback to minimum acording to SSE2 semantics.
-                            Scalar::from_i32(i32::MIN)
+                            ImmTy::from_int(i32::MIN, this.machine.layouts.i32)
                         });
-                    this.write_scalar(res, &dest)?;
+                    this.write_immediate(*res, &dest)?;
                 }
             }
             // Used to implement the _mm_packs_epi16 function.
@@ -648,8 +646,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let op = this.read_immediate(&this.project_index(&op, i)?)?;
                     let dest = this.project_index(&dest, i)?;
 
-                    let res = this.float_to_float_or_int(&op, dest.layout.ty)?;
-                    this.write_immediate(res, &dest)?;
+                    let res = this.float_to_float_or_int(&op, dest.layout)?;
+                    this.write_immediate(*res, &dest)?;
                 }
                 // For f32 -> f64, ignore the remaining
                 // For f64 -> f32, fill the remaining with zeros
@@ -685,11 +683,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let dest = this.project_index(&dest, i)?;
 
                     let res =
-                        this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                        this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
                             // Fallback to minimum acording to SSE2 semantics.
-                            Scalar::from_i32(i32::MIN)
+                            ImmTy::from_int(i32::MIN, this.machine.layouts.i32)
                         });
-                    this.write_scalar(res, &dest)?;
+                    this.write_immediate(*res, &dest)?;
                 }
                 // Fill the remaining with zeros
                 for i in op_len..dest_len {
@@ -716,12 +714,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
+                let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
                     // Fallback to minimum acording to SSE semantics.
-                    Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size)
+                    ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
                 });
 
-                this.write_scalar(res, dest)?;
+                this.write_immediate(*res, dest)?;
             }
             // Used to implement the _mm_cvtsd_ss and _mm_cvtss_sd functions.
             // Converts the first f64/f32 from `right` to f32/f64 and copies
@@ -741,8 +739,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let dest0 = this.project_index(&dest, 0)?;
                 // `float_to_float_or_int` here will convert from f64 to f32 (cvtsd2ss) or
                 // from f32 to f64 (cvtss2sd).
-                let res0 = this.float_to_float_or_int(&right0, dest0.layout.ty)?;
-                this.write_immediate(res0, &dest0)?;
+                let res0 = this.float_to_float_or_int(&right0, dest0.layout)?;
+                this.write_immediate(*res0, &dest0)?;
 
                 // Copy remianing from `left`
                 for i in 1..dest_len {
diff --git a/tests/coverage-map/status-quo/loops_branches.cov-map b/tests/coverage-map/status-quo/loops_branches.cov-map
index 56fafc0a67b..480bbfd9795 100644
--- a/tests/coverage-map/status-quo/loops_branches.cov-map
+++ b/tests/coverage-map/status-quo/loops_branches.cov-map
@@ -1,62 +1,58 @@
 Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt
-Raw bytes (262): 0x[01, 01, 36, 05, 09, 0a, 02, 00, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 25, b3, 01, b6, 01, 19, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, ca, 01, 03, 0d, 00, 0e, cf, 01, 00, 12, 00, 17, 2b, 01, 10, 00, 14, c6, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c2, 01, 01, 12, 00, 13, bb, 01, 01, 11, 00, 22, b6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, af, 01, 01, 05, 00, 06]
+Raw bytes (251): 0x[01, 01, 32, 05, 09, 00, 02, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, c3, 01, c7, 01, 0d, 00, 11, 15, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, af, 01, 11, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 25, a7, 01, aa, 01, 19, af, 01, 11, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, ba, 01, 03, 0d, 00, 0e, bf, 01, 00, 12, 00, 17, 27, 01, 10, 00, 14, b6, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b2, 01, 01, 12, 00, 13, af, 01, 01, 11, 00, 22, aa, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, a3, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 54
+Number of expressions: 50
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Expression(2, Sub), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Zero, rhs = Zero
-- expression 3 operands: lhs = Expression(51, Add), rhs = Counter(6)
-- expression 4 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 5 operands: lhs = Counter(3), rhs = Zero
-- expression 6 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 7 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 8 operands: lhs = Counter(3), rhs = Zero
-- expression 9 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 10 operands: lhs = Expression(50, Sub), rhs = Zero
-- expression 11 operands: lhs = Expression(51, Add), rhs = Counter(6)
-- expression 12 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 13 operands: lhs = Counter(3), rhs = Zero
-- expression 14 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 15 operands: lhs = Expression(50, Sub), rhs = Counter(5)
-- expression 16 operands: lhs = Expression(51, Add), rhs = Counter(6)
-- expression 17 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 18 operands: lhs = Counter(3), rhs = Zero
-- expression 19 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 20 operands: lhs = Expression(49, Sub), rhs = Counter(7)
-- expression 21 operands: lhs = Expression(50, Sub), rhs = Counter(5)
-- expression 22 operands: lhs = Expression(51, Add), rhs = Counter(6)
-- expression 23 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 24 operands: lhs = Counter(3), rhs = Zero
-- expression 25 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 26 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub)
-- expression 27 operands: lhs = Zero, rhs = Zero
-- expression 28 operands: lhs = Expression(49, Sub), rhs = Counter(7)
-- expression 29 operands: lhs = Expression(50, Sub), rhs = Counter(5)
-- expression 30 operands: lhs = Expression(51, Add), rhs = Counter(6)
-- expression 31 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 32 operands: lhs = Counter(3), rhs = Zero
-- expression 33 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 34 operands: lhs = Expression(46, Add), rhs = Counter(4)
-- expression 35 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub)
-- expression 36 operands: lhs = Zero, rhs = Zero
-- expression 37 operands: lhs = Expression(49, Sub), rhs = Counter(7)
-- expression 38 operands: lhs = Expression(50, Sub), rhs = Counter(5)
-- expression 39 operands: lhs = Expression(51, Add), rhs = Counter(6)
-- expression 40 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 41 operands: lhs = Counter(3), rhs = Zero
-- expression 42 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 43 operands: lhs = Counter(9), rhs = Expression(44, Add)
-- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(6)
-- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(4)
-- expression 46 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub)
-- expression 47 operands: lhs = Zero, rhs = Zero
-- expression 48 operands: lhs = Expression(49, Sub), rhs = Counter(7)
-- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(5)
-- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(6)
-- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
-- expression 52 operands: lhs = Counter(3), rhs = Zero
-- expression 53 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Expression(47, Add), rhs = Counter(6)
+- expression 3 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 4 operands: lhs = Counter(3), rhs = Zero
+- expression 5 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 6 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 7 operands: lhs = Counter(3), rhs = Zero
+- expression 8 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 9 operands: lhs = Expression(46, Sub), rhs = Zero
+- expression 10 operands: lhs = Expression(47, Add), rhs = Counter(6)
+- expression 11 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 12 operands: lhs = Counter(3), rhs = Zero
+- expression 13 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 14 operands: lhs = Expression(46, Sub), rhs = Counter(5)
+- expression 15 operands: lhs = Expression(47, Add), rhs = Counter(6)
+- expression 16 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 17 operands: lhs = Counter(3), rhs = Zero
+- expression 18 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 19 operands: lhs = Expression(45, Sub), rhs = Counter(7)
+- expression 20 operands: lhs = Expression(46, Sub), rhs = Counter(5)
+- expression 21 operands: lhs = Expression(47, Add), rhs = Counter(6)
+- expression 22 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 23 operands: lhs = Counter(3), rhs = Zero
+- expression 24 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 25 operands: lhs = Zero, rhs = Expression(44, Sub)
+- expression 26 operands: lhs = Expression(45, Sub), rhs = Counter(7)
+- expression 27 operands: lhs = Expression(46, Sub), rhs = Counter(5)
+- expression 28 operands: lhs = Expression(47, Add), rhs = Counter(6)
+- expression 29 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 30 operands: lhs = Counter(3), rhs = Zero
+- expression 31 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 32 operands: lhs = Expression(43, Add), rhs = Counter(4)
+- expression 33 operands: lhs = Zero, rhs = Expression(44, Sub)
+- expression 34 operands: lhs = Expression(45, Sub), rhs = Counter(7)
+- expression 35 operands: lhs = Expression(46, Sub), rhs = Counter(5)
+- expression 36 operands: lhs = Expression(47, Add), rhs = Counter(6)
+- expression 37 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 38 operands: lhs = Counter(3), rhs = Zero
+- expression 39 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 40 operands: lhs = Counter(9), rhs = Expression(41, Add)
+- expression 41 operands: lhs = Expression(42, Sub), rhs = Counter(6)
+- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4)
+- expression 43 operands: lhs = Zero, rhs = Expression(44, Sub)
+- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(7)
+- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(5)
+- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(6)
+- expression 47 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
+- expression 48 operands: lhs = Counter(3), rhs = Zero
+- expression 49 operands: lhs = Counter(4), rhs = Counter(5)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21)
@@ -65,91 +61,87 @@ Number of file 0 mappings: 20
 - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15)
     = (c1 - c2)
 - Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = ((Zero - Zero) + (c1 - c2))
+    = (Zero + (c1 - c2))
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
 - Code(Zero) at (prev + 1, 16) to (start + 1, 10)
-- Code(Expression(50, Sub)) at (prev + 3, 13) to (start + 0, 14)
+- Code(Expression(46, Sub)) at (prev + 3, 13) to (start + 0, 14)
     = (((c3 + Zero) + (c4 + c5)) - c6)
-- Code(Expression(51, Add)) at (prev + 0, 18) to (start + 0, 23)
+- Code(Expression(47, Add)) at (prev + 0, 18) to (start + 0, 23)
     = ((c3 + Zero) + (c4 + c5))
-- Code(Expression(10, Add)) at (prev + 1, 16) to (start + 0, 20)
+- Code(Expression(9, Add)) at (prev + 1, 16) to (start + 0, 20)
     = ((((c3 + Zero) + (c4 + c5)) - c6) + Zero)
-- Code(Expression(49, Sub)) at (prev + 1, 20) to (start + 0, 25)
+- Code(Expression(45, Sub)) at (prev + 1, 20) to (start + 0, 25)
     = ((((c3 + Zero) + (c4 + c5)) - c6) - c5)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(48, Sub)) at (prev + 1, 18) to (start + 0, 19)
+- Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 19)
     = (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)
-- Code(Expression(46, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = ((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7))
-- Code(Expression(45, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = (((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4)
+- Code(Expression(43, Add)) at (prev + 1, 17) to (start + 0, 34)
+    = (Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7))
+- Code(Expression(42, Sub)) at (prev + 0, 34) to (start + 0, 35)
+    = ((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4)
 - Code(Zero) at (prev + 1, 20) to (start + 1, 14)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(43, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = (c9 + ((((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6))
+- Code(Expression(40, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = (c9 + (((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6))
 
 Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt
-Raw bytes (266): 0x[01, 01, 38, 01, 05, 02, 09, 0e, 12, 00, 00, 02, 09, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 00, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ba, 01, df, 01, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 12, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, ce, 01, 02, 0d, 00, 0e, d3, 01, 00, 12, 00, 17, 33, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ca, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c6, 01, 01, 12, 00, 13, bf, 01, 01, 11, 00, 22, ba, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, b7, 01, 01, 05, 00, 06]
+Raw bytes (255): 0x[01, 01, 34, 01, 05, 02, 09, 00, 0e, 02, 09, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, c7, 01, cb, 01, 05, 0d, 11, 15, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, b3, 01, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, ae, 01, cf, 01, b3, 01, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, be, 01, 02, 0d, 00, 0e, c3, 01, 00, 12, 00, 17, 2f, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ba, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b6, 01, 01, 12, 00, 13, b3, 01, 01, 11, 00, 22, ae, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, ab, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 56
+Number of expressions: 52
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Expression(0, Sub), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(3, Sub), rhs = Expression(4, Sub)
-- expression 3 operands: lhs = Zero, rhs = Zero
-- expression 4 operands: lhs = Expression(0, Sub), rhs = Counter(2)
-- expression 5 operands: lhs = Expression(52, Add), rhs = Counter(6)
-- expression 6 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 7 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 9 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 10 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 11 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 12 operands: lhs = Expression(51, Sub), rhs = Zero
-- expression 13 operands: lhs = Expression(52, Add), rhs = Counter(6)
-- expression 14 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 15 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 17 operands: lhs = Expression(51, Sub), rhs = Counter(4)
-- expression 18 operands: lhs = Expression(52, Add), rhs = Counter(6)
-- expression 19 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 20 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 21 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 22 operands: lhs = Expression(50, Sub), rhs = Counter(7)
-- expression 23 operands: lhs = Expression(51, Sub), rhs = Counter(4)
-- expression 24 operands: lhs = Expression(52, Add), rhs = Counter(6)
-- expression 25 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 26 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 27 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 28 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub)
-- expression 29 operands: lhs = Zero, rhs = Zero
-- expression 30 operands: lhs = Expression(50, Sub), rhs = Counter(7)
-- expression 31 operands: lhs = Expression(51, Sub), rhs = Counter(4)
-- expression 32 operands: lhs = Expression(52, Add), rhs = Counter(6)
-- expression 33 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 34 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 35 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 36 operands: lhs = Expression(47, Add), rhs = Counter(5)
-- expression 37 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub)
-- expression 38 operands: lhs = Zero, rhs = Zero
-- expression 39 operands: lhs = Expression(50, Sub), rhs = Counter(7)
-- expression 40 operands: lhs = Expression(51, Sub), rhs = Counter(4)
-- expression 41 operands: lhs = Expression(52, Add), rhs = Counter(6)
-- expression 42 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 43 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 44 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 45 operands: lhs = Expression(46, Sub), rhs = Expression(55, Add)
-- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(5)
-- expression 47 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub)
-- expression 48 operands: lhs = Zero, rhs = Zero
-- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(7)
-- expression 50 operands: lhs = Expression(51, Sub), rhs = Counter(4)
-- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(6)
-- expression 52 operands: lhs = Expression(53, Add), rhs = Expression(54, Add)
-- expression 53 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 54 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 55 operands: lhs = Counter(6), rhs = Counter(9)
+- expression 2 operands: lhs = Zero, rhs = Expression(3, Sub)
+- expression 3 operands: lhs = Expression(0, Sub), rhs = Counter(2)
+- expression 4 operands: lhs = Expression(48, Add), rhs = Counter(6)
+- expression 5 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 6 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 7 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 8 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 9 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 10 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 11 operands: lhs = Expression(47, Sub), rhs = Zero
+- expression 12 operands: lhs = Expression(48, Add), rhs = Counter(6)
+- expression 13 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 14 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 15 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 16 operands: lhs = Expression(47, Sub), rhs = Counter(4)
+- expression 17 operands: lhs = Expression(48, Add), rhs = Counter(6)
+- expression 18 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 19 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 20 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 21 operands: lhs = Expression(46, Sub), rhs = Counter(7)
+- expression 22 operands: lhs = Expression(47, Sub), rhs = Counter(4)
+- expression 23 operands: lhs = Expression(48, Add), rhs = Counter(6)
+- expression 24 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 25 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 26 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 27 operands: lhs = Zero, rhs = Expression(45, Sub)
+- expression 28 operands: lhs = Expression(46, Sub), rhs = Counter(7)
+- expression 29 operands: lhs = Expression(47, Sub), rhs = Counter(4)
+- expression 30 operands: lhs = Expression(48, Add), rhs = Counter(6)
+- expression 31 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 32 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 33 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 34 operands: lhs = Expression(44, Add), rhs = Counter(5)
+- expression 35 operands: lhs = Zero, rhs = Expression(45, Sub)
+- expression 36 operands: lhs = Expression(46, Sub), rhs = Counter(7)
+- expression 37 operands: lhs = Expression(47, Sub), rhs = Counter(4)
+- expression 38 operands: lhs = Expression(48, Add), rhs = Counter(6)
+- expression 39 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 40 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 41 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 42 operands: lhs = Expression(43, Sub), rhs = Expression(51, Add)
+- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(5)
+- expression 44 operands: lhs = Zero, rhs = Expression(45, Sub)
+- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(7)
+- expression 46 operands: lhs = Expression(47, Sub), rhs = Counter(4)
+- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(6)
+- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
+- expression 49 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 50 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 51 operands: lhs = Counter(6), rhs = Counter(9)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17)
 - Code(Zero) at (prev + 1, 18) to (start + 1, 10)
@@ -157,31 +149,31 @@ Number of file 0 mappings: 20
     = (c0 - c1)
 - Code(Zero) at (prev + 1, 23) to (start + 0, 27)
 - Code(Zero) at (prev + 0, 28) to (start + 0, 30)
-- Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 15)
+- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 15)
     = ((c0 - c1) - c2)
 - Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = ((Zero - Zero) + ((c0 - c1) - c2))
+    = (Zero + ((c0 - c1) - c2))
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
-- Code(Expression(51, Sub)) at (prev + 2, 13) to (start + 0, 14)
+- Code(Expression(47, Sub)) at (prev + 2, 13) to (start + 0, 14)
     = (((c1 + c3) + (c4 + c5)) - c6)
-- Code(Expression(52, Add)) at (prev + 0, 18) to (start + 0, 23)
+- Code(Expression(48, Add)) at (prev + 0, 18) to (start + 0, 23)
     = ((c1 + c3) + (c4 + c5))
-- Code(Expression(12, Add)) at (prev + 1, 16) to (start + 0, 21)
+- Code(Expression(11, Add)) at (prev + 1, 16) to (start + 0, 21)
     = ((((c1 + c3) + (c4 + c5)) - c6) + Zero)
 - Code(Zero) at (prev + 0, 22) to (start + 1, 14)
-- Code(Expression(50, Sub)) at (prev + 2, 20) to (start + 0, 25)
+- Code(Expression(46, Sub)) at (prev + 2, 20) to (start + 0, 25)
     = ((((c1 + c3) + (c4 + c5)) - c6) - c4)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(49, Sub)) at (prev + 1, 18) to (start + 0, 19)
+- Code(Expression(45, Sub)) at (prev + 1, 18) to (start + 0, 19)
     = (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)
-- Code(Expression(47, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = ((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7))
-- Code(Expression(46, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = (((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5)
+- Code(Expression(44, Add)) at (prev + 1, 17) to (start + 0, 34)
+    = (Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7))
+- Code(Expression(43, Sub)) at (prev + 0, 34) to (start + 0, 35)
+    = ((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(45, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = ((((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9))
+- Code(Expression(42, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = (((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9))
 
 Function name: loops_branches::main
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02]
diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir
index 18a663d9f9e..1d3317efd41 100644
--- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir
@@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 {
         StorageLive(_2);                 // scope 0 at $DIR/spans.rs:10:11: 10:13
         _2 = &_1;                        // scope 0 at $DIR/spans.rs:10:11: 10:13
         _0 = inner(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/spans.rs:10:5: 10:14
-                                         // mir::Constant
+                                         // mir::ConstOperand
                                          // + span: $DIR/spans.rs:10:5: 10:10
-                                         // + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
+                                         // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
     }
 
     bb1: {
diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
index 1c02fb72bcd..aba66861f7d 100644
--- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
@@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 {
         StorageLive(_2);                 // scope 0 at $DIR/spans.rs:10:11: 10:13
         _2 = &_1;                        // scope 0 at $DIR/spans.rs:10:11: 10:13
         _0 = inner(move _2) -> [return: bb1, unwind continue]; // scope 0 at $DIR/spans.rs:10:5: 10:14
-                                         // mir::Constant
+                                         // mir::ConstOperand
                                          // + span: $DIR/spans.rs:10:5: 10:10
-                                         // + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
+                                         // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
     }
 
     bb1: {
diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout
index f5981045b03..38a3965f0c5 100644
--- a/tests/run-make/issue-88756-default-output/output-default.stdout
+++ b/tests/run-make/issue-88756-default-output/output-default.stdout
@@ -133,9 +133,6 @@ Options:
                         Path string to force loading static files from in
                         output pages. If not set, uses combinations of '../'
                         to reach the documentation root.
-        --disable-per-crate-search 
-                        disables generating the crate selector on the search
-                        box
         --persist-doctests PATH
                         Directory to persist doctest executables into
         --show-coverage 
diff --git a/tests/rustdoc/no-crate-filter.rs b/tests/rustdoc/no-crate-filter.rs
deleted file mode 100644
index b2f89906480..00000000000
--- a/tests/rustdoc/no-crate-filter.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![crate_name = "foo"]
-
-// compile-flags: -Z unstable-options --disable-per-crate-search
-
-// @!has 'foo/struct.Foo.html' '//*[id="crate-search"]' ''
-pub struct Foo;
diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/rfc-2632-const-trait-impl.rs
index 5d742dc391a..7f56b2ffeb8 100644
--- a/tests/rustdoc/rfc-2632-const-trait-impl.rs
+++ b/tests/rustdoc/rfc-2632-const-trait-impl.rs
@@ -5,6 +5,8 @@
 // To future blessers: make sure that `const_trait_impl` is
 // stabilized when changing `@!has` to `@has`, and please do
 // not remove this test.
+//
+// FIXME(effects) add `const_trait` to `Fn` so we use `~const`
 #![feature(const_trait_impl)]
 #![crate_name = "foo"]
 
@@ -22,9 +24,9 @@ pub trait Tr<T> {
     // @has - '//section[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn'
     // @!has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
     // @has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn'
-    fn a<A: ~const Fn() + ~const Destruct>()
+    fn a<A: /* ~const */ Fn() + ~const Destruct>()
     where
-        Option<A>: ~const Fn() + ~const Destruct,
+        Option<A>: /* ~const */ Fn() + ~const Destruct,
     {
     }
 }
@@ -34,13 +36,13 @@ pub trait Tr<T> {
 // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/a[@class="trait"]' 'Fn'
 // @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where"]' '~const'
 // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn'
-impl<T: ~const Fn() + ~const Destruct> const Tr<T> for T
+impl<T: /* ~const */ Fn() + ~const Destruct> const Tr<T> for T
 where
-    Option<T>: ~const Fn() + ~const Destruct,
+    Option<T>: /* ~const */ Fn() + ~const Destruct,
 {
-    fn a<A: ~const Fn() + ~const Destruct>()
+    fn a<A: /* ~const */ Fn() + ~const Destruct>()
     where
-        Option<A>: ~const Fn() + ~const Destruct,
+        Option<A>: /* ~const */ Fn() + ~const Destruct,
     {
     }
 }
@@ -49,9 +51,9 @@ where
 // @has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Fn'
 // @!has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' '~const'
 // @has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' ': Fn'
-pub const fn foo<F: ~const Fn() + ~const Destruct>()
+pub const fn foo<F: /* ~const */ Fn() + ~const Destruct>()
 where
-    Option<F>: ~const Fn() + ~const Destruct,
+    Option<F>: /* ~const */ Fn() + ~const Destruct,
 {
     F::a()
 }
@@ -61,9 +63,9 @@ impl<T> S<T> {
     // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn'
     // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
     // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn'
-    pub const fn foo<B, C: ~const Fn() + ~const Destruct>()
+    pub const fn foo<B, C: /* ~const */ Fn() + ~const Destruct>()
     where
-        B: ~const Fn() + ~const Destruct,
+        B: /* ~const */ Fn() + ~const Destruct,
     {
         B::a()
     }
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs
index 642b58b0753..283d87d3eb6 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs
@@ -1,7 +1,7 @@
 // check-fail
 // Tests that a doc comment will not preclude a field from being considered a diagnostic argument
 // normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr"
-// normalize-stderr-test "diagnostic_builder\.rs:[0-9]+:[0-9]+" -> "diagnostic_builder.rs:LL:CC"
+// normalize-stderr-test "(COMPILER_DIR/.*\.rs):[0-9]+:[0-9]+" -> "$1:LL:CC"
 
 // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
 // changing the output of this test. Since Subdiagnostic is strictly internal to the compiler
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr
index e014fc8c693..70d7b3225b5 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr
@@ -23,7 +23,7 @@ LL |     arg: NotIntoDiagnosticArg,
    |
    = help: normalized in stderr
 note: required by a bound in `Diagnostic::set_arg`
-  --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:968:5
+  --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/associated-inherent-types/issue-111879-1.stderr b/tests/ui/associated-inherent-types/issue-111879-1.stderr
index 689b45e09aa..bf35f2bb5b5 100644
--- a/tests/ui/associated-inherent-types/issue-111879-1.stderr
+++ b/tests/ui/associated-inherent-types/issue-111879-1.stderr
@@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type
 LL | fn main(_: for<'a> fn(Foo<fn(&'a ())>::Assoc)) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn(for<'a> fn(Foo<fn(&'a ())>::Assoc))`
+   = note: expected signature `fn()`
+              found signature `fn(for<'a> fn(&'a ()))`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs
new file mode 100644
index 00000000000..bba886f175e
--- /dev/null
+++ b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs
@@ -0,0 +1,7 @@
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+
+pub trait Foo {
+    async fn test();
+}
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr
index 18185b75554..7e59d94d456 100644
--- a/tests/ui/async-await/in-trait/missing-send-bound.stderr
+++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr
@@ -15,6 +15,11 @@ note: required by a bound in `assert_is_send`
    |
 LL | fn assert_is_send(_: impl Send) {}
    |                           ^^^^ required by this bound in `assert_is_send`
+help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::bar`
+   |
+LL -     async fn bar();
+LL +     fn bar() -> impl std::future::Future<Output = ()> + Send;
+   |
 
 error: aborting due to previous error
 
diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed
new file mode 100644
index 00000000000..33c00587439
--- /dev/null
+++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+// edition: 2021
+
+#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
+#![allow(unused)]
+
+trait Foo {
+    fn test() -> impl std::future::Future<Output = ()> + Send { async {} }
+    fn test2() -> impl std::future::Future<Output = i32> + Send {async { 1 + 2 } }
+}
+
+fn bar<T: Foo>() {
+    fn needs_send(_: impl Send) {}
+    needs_send(T::test());
+    //~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely
+    needs_send(T::test2());
+    //~^ ERROR `impl Future<Output = i32>` cannot be sent between threads safely
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs
new file mode 100644
index 00000000000..96b623d6988
--- /dev/null
+++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+// edition: 2021
+
+#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
+#![allow(unused)]
+
+trait Foo {
+    async fn test() -> () {}
+    async fn test2() -> i32 { 1 + 2 }
+}
+
+fn bar<T: Foo>() {
+    fn needs_send(_: impl Send) {}
+    needs_send(T::test());
+    //~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely
+    needs_send(T::test2());
+    //~^ ERROR `impl Future<Output = i32>` cannot be sent between threads safely
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr
new file mode 100644
index 00000000000..4319a14118b
--- /dev/null
+++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr
@@ -0,0 +1,43 @@
+error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely
+  --> $DIR/send-on-async-fn-in-trait.rs:14:16
+   |
+LL |     needs_send(T::test());
+   |     ---------- ^^^^^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Send` is not implemented for `impl Future<Output = ()>`
+note: required by a bound in `needs_send`
+  --> $DIR/send-on-async-fn-in-trait.rs:13:27
+   |
+LL |     fn needs_send(_: impl Send) {}
+   |                           ^^^^ required by this bound in `needs_send`
+help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::test`
+   |
+LL -     async fn test() -> () {}
+LL +     fn test() -> impl std::future::Future<Output = ()> + Send { async {} }
+   |
+
+error[E0277]: `impl Future<Output = i32>` cannot be sent between threads safely
+  --> $DIR/send-on-async-fn-in-trait.rs:16:16
+   |
+LL |     needs_send(T::test2());
+   |     ---------- ^^^^^^^^^^ `impl Future<Output = i32>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Send` is not implemented for `impl Future<Output = i32>`
+note: required by a bound in `needs_send`
+  --> $DIR/send-on-async-fn-in-trait.rs:13:27
+   |
+LL |     fn needs_send(_: impl Send) {}
+   |                           ^^^^ required by this bound in `needs_send`
+help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::test2`
+   |
+LL -     async fn test2() -> i32 { 1 + 2 }
+LL +     fn test2() -> impl std::future::Future<Output = i32> + Send {async { 1 + 2 } }
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs
new file mode 100644
index 00000000000..83b69d72a96
--- /dev/null
+++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs
@@ -0,0 +1,15 @@
+// aux-build:foreign-async-fn.rs
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+
+extern crate foreign_async_fn;
+use foreign_async_fn::Foo;
+
+fn bar<T: Foo>() {
+    fn needs_send(_: impl Send) {}
+    needs_send(T::test());
+    //~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr
new file mode 100644
index 00000000000..f337a04ba19
--- /dev/null
+++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr
@@ -0,0 +1,23 @@
+error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely
+  --> $DIR/send-on-foreign-async-fn-in-trait.rs:11:16
+   |
+LL |     needs_send(T::test());
+   |     ---------- ^^^^^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Send` is not implemented for `impl Future<Output = ()>`
+note: `<T as Foo>::test` is an `async fn` in trait, which does not automatically imply that its future is `Send`
+  --> $DIR/auxiliary/foreign-async-fn.rs:6:5
+   |
+LL |     async fn test();
+   |     ^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_send`
+  --> $DIR/send-on-foreign-async-fn-in-trait.rs:10:27
+   |
+LL |     fn needs_send(_: impl Send) {}
+   |                           ^^^^ required by this bound in `needs_send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/large_moves.attribute.stderr b/tests/ui/async-await/large_moves.attribute.stderr
deleted file mode 100644
index 1d1999462ce..00000000000
--- a/tests/ui/async-await/large_moves.attribute.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error: moving 10024 bytes
-  --> $DIR/large_moves.rs:21:14
-   |
-LL |     let z = (x, 42);
-   |              ^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-note: the lint level is defined here
-  --> $DIR/large_moves.rs:1:9
-   |
-LL | #![deny(large_assignments)]
-   |         ^^^^^^^^^^^^^^^^^
-
-error: moving 10024 bytes
-  --> $DIR/large_moves.rs:22:13
-   |
-LL |     let a = z.0;
-   |             ^^^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-error: moving 9999 bytes
-  --> $DIR/large_moves.rs:27:13
-   |
-LL |     let _ = NotBox::new([0; 9999]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-error: moving 9999 bytes
-  --> $DIR/large_moves.rs:41:13
-   |
-LL |             data,
-   |             ^^^^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/async-await/large_moves.option.stderr b/tests/ui/async-await/large_moves.option.stderr
deleted file mode 100644
index 1d1999462ce..00000000000
--- a/tests/ui/async-await/large_moves.option.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error: moving 10024 bytes
-  --> $DIR/large_moves.rs:21:14
-   |
-LL |     let z = (x, 42);
-   |              ^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-note: the lint level is defined here
-  --> $DIR/large_moves.rs:1:9
-   |
-LL | #![deny(large_assignments)]
-   |         ^^^^^^^^^^^^^^^^^
-
-error: moving 10024 bytes
-  --> $DIR/large_moves.rs:22:13
-   |
-LL |     let a = z.0;
-   |             ^^^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-error: moving 9999 bytes
-  --> $DIR/large_moves.rs:27:13
-   |
-LL |     let _ = NotBox::new([0; 9999]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-error: moving 9999 bytes
-  --> $DIR/large_moves.rs:41:13
-   |
-LL |             data,
-   |             ^^^^ value moved from here
-   |
-   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs
index 6ee2320a603..3a6f8908b21 100644
--- a/tests/ui/borrowck/issue-92157.rs
+++ b/tests/ui/borrowck/issue-92157.rs
@@ -9,7 +9,7 @@ extern {}
 
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
-    //~^ ERROR: incorrect number of parameters for the `start` lang item
+    //~^ ERROR lang item `start` function has wrong type [E0308]
     40+2
 }
 
diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr
index a4010d73d05..a46b1288911 100644
--- a/tests/ui/borrowck/issue-92157.stderr
+++ b/tests/ui/borrowck/issue-92157.stderr
@@ -1,11 +1,12 @@
-error: incorrect number of parameters for the `start` lang item
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/issue-92157.rs:11:1
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: the `start` lang item should have four parameters, but found 3
-   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+   = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _`
+              found signature `fn(fn() -> T, isize, *const *const u8) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr
index e773d5d83cc..c705152d9fc 100644
--- a/tests/ui/check-cfg/values-target-json.stderr
+++ b/tests/ui/check-cfg/values-target-json.stderr
@@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")]
    |                   |
    |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 1f775814656..b381f5a4a0a 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")]
    |                   |
    |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index bfebf66701b..658a0b7b2a0 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -10,6 +10,66 @@ error[E0635]: unknown feature `const_cmp`
 LL | #![feature(const_cmp)]
    |            ^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:15:15
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |               ^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:15:15
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |               ^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:22:15
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |               ^^^^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:22:15
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |               ^^^^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:29:15
+   |
+LL |     T: ~const FnOnce<()>,
+   |               ^^^^^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:29:15
+   |
+LL |     T: ~const FnOnce<()>,
+   |               ^^^^^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:36:15
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |               ^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:36:15
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |               ^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:50:15
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |               ^^^^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:50:15
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |               ^^^^^^^^^
+
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0635`.
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.rs b/tests/ui/consts/unstable-const-fn-in-libcore.rs
index 61e28117ed4..b62a74039f6 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.rs
@@ -1,3 +1,5 @@
+// known-bug: #110395
+// FIXME check-pass
 // This is a non-regression test for const-qualification of unstable items in libcore
 // as explained in issue #67053.
 // const-qualification could miss some `const fn`s if they were unstable and the feature
@@ -15,12 +17,12 @@ impl<T> Opt<T> {
     #[rustc_const_unstable(feature = "foo", issue = "none")]
     #[stable(feature = "rust1", since = "1.0.0")]
     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-    //~^ ERROR destructor of
-    //~| ERROR destructor of
+    //FIXME ~^ ERROR destructor of
+    //FIXME ~| ERROR destructor of
         match self {
             Opt::Some(t) => t,
             Opt::None => f(),
-            //~^ ERROR cannot call
+            //FIXME ~^ ERROR cannot call
         }
     }
 }
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index 95d7b7e8537..b75f99a720f 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,34 +1,8 @@
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/unstable-const-fn-in-libcore.rs:22:26
-   |
-LL |             Opt::None => f(),
-   |                          ^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T + ~const std::ops::FnOnce<()>>(self, f: F) -> T {
-   |                                                     +++++++++++++++++++++++++++++
-
-error[E0493]: destructor of `F` cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:17:60
-   |
-LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-   |                                                            ^ the destructor for this type cannot be evaluated in constant functions
-...
-LL |     }
-   |     - value is dropped here
-
-error[E0493]: destructor of `Opt<T>` cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:17:54
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/unstable-const-fn-in-libcore.rs:19:39
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-   |                                                      ^^^^ the destructor for this type cannot be evaluated in constant functions
-...
-LL |     }
-   |     - value is dropped here
+   |                                       ^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0015, E0493.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/entry-point/auxiliary/bad_main_functions.rs b/tests/ui/entry-point/auxiliary/bad_main_functions.rs
new file mode 100644
index 00000000000..4649be99e6f
--- /dev/null
+++ b/tests/ui/entry-point/auxiliary/bad_main_functions.rs
@@ -0,0 +1,2 @@
+pub fn boilerplate(x: u8) {}
+//~^ ERROR: `main` function has wrong type [E0580]
diff --git a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs
new file mode 100644
index 00000000000..0a115dd3b08
--- /dev/null
+++ b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs
@@ -0,0 +1,6 @@
+// aux-build:bad_main_functions.rs
+
+#![feature(imported_main)]
+
+extern crate bad_main_functions;
+pub use bad_main_functions::boilerplate as main;
diff --git a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr
new file mode 100644
index 00000000000..3c68933101c
--- /dev/null
+++ b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr
@@ -0,0 +1,12 @@
+error[E0580]: `main` function has wrong type
+  --> $DIR/auxiliary/bad_main_functions.rs:1:1
+   |
+LL | pub fn boilerplate(x: u8) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn()`
+              found signature `fn(u8)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0580`.
diff --git a/tests/ui/error-codes/E0308.stderr b/tests/ui/error-codes/E0308.stderr
index 187b775f92d..141abed6032 100644
--- a/tests/ui/error-codes/E0308.stderr
+++ b/tests/ui/error-codes/E0308.stderr
@@ -1,11 +1,11 @@
 error[E0308]: intrinsic has wrong type
-  --> $DIR/E0308.rs:6:5
+  --> $DIR/E0308.rs:6:20
    |
 LL |     fn size_of<T>();
-   |     ^^^^^^^^^^^^^^^^ expected `()`, found `usize`
+   |                    ^ expected `usize`, found `()`
    |
-   = note: expected fn pointer `extern "rust-intrinsic" fn()`
-              found fn pointer `extern "rust-intrinsic" fn() -> usize`
+   = note: expected signature `extern "rust-intrinsic" fn() -> usize`
+              found signature `extern "rust-intrinsic" fn()`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/extern/extern-main-fn.stderr b/tests/ui/extern/extern-main-fn.stderr
index 136c9575382..846102670a8 100644
--- a/tests/ui/extern/extern-main-fn.stderr
+++ b/tests/ui/extern/extern-main-fn.stderr
@@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type
 LL | extern "C" fn main() {}
    | ^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn
    |
-   = note: expected fn pointer `fn()`
-              found fn pointer `extern "C" fn()`
+   = note: expected signature `fn()`
+              found signature `extern "C" fn()`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/fn/bad-main.stderr b/tests/ui/fn/bad-main.stderr
index 675b66d0578..65140a0794f 100644
--- a/tests/ui/fn/bad-main.stderr
+++ b/tests/ui/fn/bad-main.stderr
@@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type
 LL | fn main(x: isize) { }
    | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn(isize)`
+   = note: expected signature `fn()`
+              found signature `fn(isize)`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index 5fbba9a85ca..ada8fd7fa50 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,25 +1,8 @@
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/normalize-tait-in-const.rs:26:5
-   |
-LL |     fun(filter_positive());
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct + ~const std::ops::Fn<(&Alias<'_>,)>>(fun: F) {
-   |                                                                              ++++++++++++++++++++++++++++++++++++
-
-error[E0493]: destructor of `F` cannot be evaluated at compile-time
-  --> $DIR/normalize-tait-in-const.rs:25:79
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/normalize-tait-in-const.rs:25:42
    |
 LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                                                               ^^^ the destructor for this type cannot be evaluated in constant functions
-LL |     fun(filter_positive());
-LL | }
-   | - value is dropped here
+   |                                          ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0015, E0493.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/inline-const/promotion.rs b/tests/ui/inline-const/promotion.rs
new file mode 100644
index 00000000000..242959c6b51
--- /dev/null
+++ b/tests/ui/inline-const/promotion.rs
@@ -0,0 +1,22 @@
+#![feature(inline_const)]
+#![allow(arithmetic_overflow, unconditional_panic)]
+
+// The only way to have promoteds that fail is in `const fn` called from `const`/`static`.
+// Make sure that in a `const` block, we do not promote such calls.
+const fn div_by_zero() -> i32 {
+    1 / 0
+}
+
+const fn mk_false() -> bool {
+    false
+}
+
+fn main() {
+    let v = const {
+        if mk_false() {
+            let _x: &'static i32 = &div_by_zero();
+            //~^ ERROR: temporary value dropped while borrowed
+        }
+        42
+    };
+}
diff --git a/tests/ui/inline-const/promotion.stderr b/tests/ui/inline-const/promotion.stderr
new file mode 100644
index 00000000000..795fc8f5921
--- /dev/null
+++ b/tests/ui/inline-const/promotion.stderr
@@ -0,0 +1,14 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promotion.rs:17:37
+   |
+LL |             let _x: &'static i32 = &div_by_zero();
+   |                     ------------    ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
+   |                     |
+   |                     type annotation requires that borrow lasts for `'static`
+LL |
+LL |         }
+   |         - temporary value is freed at the end of this statement
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs
index b99bb39d062..30b8a21269a 100644
--- a/tests/ui/intrinsics/intrinsic-alignment.rs
+++ b/tests/ui/intrinsics/intrinsic-alignment.rs
@@ -16,6 +16,7 @@ mod rusti {
           target_os = "emscripten",
           target_os = "freebsd",
           target_os = "fuchsia",
+          target_os = "hurd",
           target_os = "illumos",
           target_os = "linux",
           target_os = "macos",
diff --git a/tests/ui/issues/issue-9575.stderr b/tests/ui/issues/issue-9575.stderr
index 5b8ce84a071..e49eac3babf 100644
--- a/tests/ui/issues/issue-9575.stderr
+++ b/tests/ui/issues/issue-9575.stderr
@@ -4,8 +4,8 @@ error[E0308]: `#[start]` function has wrong type
 LL | fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: expected fn pointer `fn(isize, *const *const u8) -> _`
-              found fn pointer `fn(isize, *const *const u8, *const u8) -> _`
+   = note: expected signature `fn(isize, *const *const u8) -> _`
+              found signature `fn(isize, *const *const u8, *const u8) -> _`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/lang-items/start_lang_item_args.argc.stderr b/tests/ui/lang-items/start_lang_item_args.argc.stderr
index 65c99a93c75..66d4397a293 100644
--- a/tests/ui/lang-items/start_lang_item_args.argc.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.argc.stderr
@@ -1,8 +1,12 @@
-error: parameter 2 of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:75:38
    |
 LL | fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize {
-   |                                      ^^ help: change the type from `i8` to `isize`
+   |                                      ^^ expected `isize`, found `i8`
+   |
+   = note: expected signature `fn(fn() -> _, isize, _, _) -> _`
+              found signature `fn(fn() -> _, i8, _, _) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.argv.stderr b/tests/ui/lang-items/start_lang_item_args.argv.stderr
index f0947a9b3e9..53d776cd846 100644
--- a/tests/ui/lang-items/start_lang_item_args.argv.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.argv.stderr
@@ -1,8 +1,12 @@
-error: parameter 3 of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:89:52
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize {
-   |                                                    ^^ help: change the type from `u8` to `*const *const u8`
+   |                                                    ^^ expected `*const *const u8`, found `u8`
+   |
+   = note: expected signature `fn(fn() -> _, _, *const *const u8, _) -> _`
+              found signature `fn(fn() -> _, _, u8, _) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
index 08efd5088f9..7d002e090b5 100644
--- a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
@@ -1,13 +1,12 @@
-error: parameter 3 of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:82:52
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize {
-   |                                                    ^^^^^^^^^^^^^^^^^^^
+   |                                                    ^^^^^^^^^^^^^^^^^^^ expected `u8`, found `usize`
    |
-help: change the type from `*const *const usize` to `*const *const u8`
-   |
-LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-   |                                                    ~~~~~~~~~~~~~~~~
+   = note: expected signature `fn(fn() -> _, _, *const *const u8, _) -> _`
+              found signature `fn(fn() -> _, _, *const *const usize, _) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.main_args.stderr b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
index c20a744661d..91994b9d742 100644
--- a/tests/ui/lang-items/start_lang_item_args.main_args.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
@@ -1,13 +1,12 @@
-error: parameter 1 of the `start` lang item is incorrect
-  --> $DIR/start_lang_item_args.rs:61:20
+error[E0308]: lang item `start` function has wrong type
+  --> $DIR/start_lang_item_args.rs:61:1
    |
 LL | fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-   |                    ^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-help: change the type from `fn(i32) -> T` to `fn() -> T`
-   |
-LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-   |                    ~~~~~~~~~
+   = note: expected signature `fn(fn() -> _, _, _, _) -> _`
+              found signature `fn(fn(i32) -> _, _, _, _) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
index 8f967252f49..4582b69850c 100644
--- a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
@@ -1,13 +1,14 @@
-error: parameter 1 of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:68:20
    |
 LL | fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-   |                    ^^^^^^^^^^^
+   |          -         ^^^^^^^^^^^ expected type parameter `T`, found `u16`
+   |          |
+   |          this type parameter
    |
-help: change the type from `fn() -> u16` to `fn() -> T`
-   |
-LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-   |                    ~~~~~~~~~
+   = note: expected signature `fn(fn() -> T, _, _, _) -> _`
+              found signature `fn(fn() -> u16, _, _, _) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
index deb37b868ea..87940d05e78 100644
--- a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
@@ -1,8 +1,12 @@
-error: parameter 1 of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:54:20
    |
 LL | fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-   |                    ^^^ help: change the type from `u64` to `fn() -> T`
+   |                    ^^^ expected fn pointer, found `u64`
+   |
+   = note: expected signature `fn(fn() -> T, _, _, _) -> _`
+              found signature `fn(u64, _, _, _) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
index 004c2a67f62..5363871e202 100644
--- a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
@@ -1,11 +1,12 @@
-error: incorrect number of parameters for the `start` lang item
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:15:1
    |
 LL | fn start<T>() -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: the `start` lang item should have four parameters, but found 0
-   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+   = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _`
+              found signature `fn() -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
index 1d8285b5900..2bb29f911a1 100644
--- a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
@@ -1,8 +1,12 @@
-error: the return type of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:29:84
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
-   |                                                                                    ^ help: change the type from `()` to `isize`
+   |                                                                                    ^ expected `isize`, found `()`
+   |
+   = note: expected signature `fn(fn() -> _, _, _, _) -> isize`
+              found signature `fn(fn() -> _, _, _, _)`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
index e545a750f24..f873f7614bd 100644
--- a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
@@ -1,11 +1,12 @@
-error: incorrect number of parameters for the `start` lang item
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:22:1
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: the `start` lang item should have four parameters, but found 3
-   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+   = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _`
+              found signature `fn(fn() -> T, isize, *const *const u8) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.rs b/tests/ui/lang-items/start_lang_item_args.rs
index 0dbfba39cb6..4a0302bcb15 100644
--- a/tests/ui/lang-items/start_lang_item_args.rs
+++ b/tests/ui/lang-items/start_lang_item_args.rs
@@ -13,33 +13,33 @@ pub trait Sized {}
 #[cfg(missing_all_args)]
 #[lang = "start"]
 fn start<T>() -> isize {
-    //[missing_all_args]~^ ERROR incorrect number of parameters
+    //[missing_all_args]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(missing_sigpipe_arg)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
-    //[missing_sigpipe_arg]~^ ERROR incorrect number of parameters
+    //[missing_sigpipe_arg]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(missing_ret)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
-//[missing_ret]~^ ERROR the return type of the `start` lang item is incorrect
+//[missing_ret]~^ ERROR lang item `start` function has wrong type [E0308]
 
 #[cfg(start_ret)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 {
-    //[start_ret]~^ ERROR the return type of the `start` lang item is incorrect
+    //[start_ret]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(too_many_args)]
 #[lang = "start"]
 fn start<T>(
-    //[too_many_args]~^ ERROR incorrect number of parameters
+    //[too_many_args]~^ ERROR lang item `start` function has wrong type [E0308]
     _main: fn() -> T,
     _argc: isize,
     _argv: *const *const u8,
@@ -52,49 +52,49 @@ fn start<T>(
 #[cfg(main_ty)]
 #[lang = "start"]
 fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-    //[main_ty]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    //[main_ty]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(main_args)]
 #[lang = "start"]
 fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-    //[main_args]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    //[main_args]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(main_ret)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
-    //[main_ret]~^ ERROR parameter 1 of the `start` lang item is incorrect
+    //[main_ret]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(argc)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize {
-    //[argc]~^ ERROR parameter 2 of the `start` lang item is incorrect
+    //[argc]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(argv_inner_ptr)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize {
-    //[argv_inner_ptr]~^ ERROR parameter 3 of the `start` lang item is incorrect
+    //[argv_inner_ptr]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(argv)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize {
-    //[argv]~^ ERROR parameter 3 of the `start` lang item is incorrect
+    //[argv]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
 #[cfg(sigpipe)]
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize {
-    //[sigpipe]~^ ERROR parameter 4 of the `start` lang item is incorrect
+    //[sigpipe]~^ ERROR lang item `start` function has wrong type [E0308]
     100
 }
 
diff --git a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
index b20ae312801..280d423bd7e 100644
--- a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
@@ -1,8 +1,12 @@
-error: parameter 4 of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:96:80
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize {
-   |                                                                                ^^^ help: change the type from `i64` to `u8`
+   |                                                                                ^^^ expected `u8`, found `i64`
+   |
+   = note: expected signature `fn(fn() -> _, _, _, u8) -> _`
+              found signature `fn(fn() -> _, _, _, i64) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
index 935d5f3c8b4..4e4f8a5cdb3 100644
--- a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
@@ -1,8 +1,12 @@
-error: the return type of the `start` lang item is incorrect
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:34:87
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 {
-   |                                                                                       ^^ help: change the type from `u8` to `isize`
+   |                                                                                       ^^ expected `isize`, found `u8`
+   |
+   = note: expected signature `fn(fn() -> _, _, _, _) -> isize`
+              found signature `fn(fn() -> _, _, _, _) -> u8`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
index 30a7ed18a3d..085d4b1f238 100644
--- a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
@@ -1,4 +1,4 @@
-error: incorrect number of parameters for the `start` lang item
+error[E0308]: lang item `start` function has wrong type
   --> $DIR/start_lang_item_args.rs:41:1
    |
 LL | / fn start<T>(
@@ -8,10 +8,11 @@ LL | |     _argc: isize,
 ...  |
 LL | |     _extra_arg: (),
 LL | | ) -> isize {
-   | |__________^
+   | |__________^ incorrect number of function parameters
    |
-   = note: the `start` lang item should have four parameters, but found 5
-   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+   = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _`
+              found signature `fn(fn() -> T, isize, *const *const u8, u8, ()) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.rs b/tests/ui/lang-items/start_lang_item_with_target_feature.rs
new file mode 100644
index 00000000000..3052b7bb563
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_with_target_feature.rs
@@ -0,0 +1,19 @@
+// only-x86_64
+// check-fail
+
+#![feature(lang_items, no_core, target_feature_11)]
+#![no_core]
+
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "start"]
+#[target_feature(enable = "avx2")]
+//~^ ERROR `start` language item function is not allowed to have `#[target_feature]`
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    0
+}
+
+fn main() {}
diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr
new file mode 100644
index 00000000000..ff55a1365e4
--- /dev/null
+++ b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr
@@ -0,0 +1,11 @@
+error: `start` language item function is not allowed to have `#[target_feature]`
+  --> $DIR/start_lang_item_with_target_feature.rs:13:1
+   |
+LL | #[target_feature(enable = "avx2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+   | ------------------------------------------------------------------------------------------- `start` language item function is not allowed to have `#[target_feature]`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs
index 9c8c636812e..43ceffb71e5 100644
--- a/tests/ui/lint/invalid_from_utf8.rs
+++ b/tests/ui/lint/invalid_from_utf8.rs
@@ -1,6 +1,8 @@
 // check-pass
 
+#![feature(inline_const)]
 #![feature(concat_bytes)]
+
 #![warn(invalid_from_utf8_unchecked)]
 #![warn(invalid_from_utf8)]
 
@@ -90,4 +92,29 @@ pub fn from_utf8() {
     }
 }
 
+pub fn from_utf8_with_indirections() {
+    let mut a = [99, 108, 130, 105, 112, 112, 121];
+    std::str::from_utf8_mut(&mut a);
+    //~^ WARN calls to `std::str::from_utf8_mut`
+    let mut b = &mut a;
+    let mut c = b;
+    std::str::from_utf8_mut(c);
+    //~^ WARN calls to `std::str::from_utf8_mut`
+    let mut c = &[99, 108, 130, 105, 112, 112, 121];
+    std::str::from_utf8(c);
+    //~^ WARN calls to `std::str::from_utf8`
+    const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
+    std::str::from_utf8(&INVALID_1);
+    //~^ WARN calls to `std::str::from_utf8`
+    static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
+    std::str::from_utf8(&INVALID_2);
+    //~^ WARN calls to `std::str::from_utf8`
+    const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121];
+    std::str::from_utf8(INVALID_3);
+    //~^ WARN calls to `std::str::from_utf8`
+    const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] };
+    std::str::from_utf8(INVALID_4);
+    //~^ WARN calls to `std::str::from_utf8`
+}
+
 fn main() {}
diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr
index 8e00d3bf872..884165d4f12 100644
--- a/tests/ui/lint/invalid_from_utf8.stderr
+++ b/tests/ui/lint/invalid_from_utf8.stderr
@@ -1,43 +1,43 @@
 warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:19:9
+  --> $DIR/invalid_from_utf8.rs:21:9
    |
 LL |         std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^
-   |                                           |
-   |                                           the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
+   |                                                |
+   |                                                the literal was valid UTF-8 up to the 2 bytes
    |
 note: the lint level is defined here
-  --> $DIR/invalid_from_utf8.rs:4:9
+  --> $DIR/invalid_from_utf8.rs:6:9
    |
 LL | #![warn(invalid_from_utf8_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:21:9
+  --> $DIR/invalid_from_utf8.rs:23:9
    |
 LL |         std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^
-   |                                           |
-   |                                           the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                                                |
+   |                                                the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:39:9
+  --> $DIR/invalid_from_utf8.rs:41:9
    |
 LL |         std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^
-   |                                       |
-   |                                       the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
+   |                                        |
+   |                                        the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:41:9
+  --> $DIR/invalid_from_utf8.rs:43:9
    |
 LL |         std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^
-   |                                       |
-   |                                       the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                                        |
+   |                                        the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:43:9
+  --> $DIR/invalid_from_utf8.rs:45:9
    |
 LL |         std::str::from_utf8_unchecked(b"cl\x82ippy");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^
@@ -45,7 +45,7 @@ LL |         std::str::from_utf8_unchecked(b"cl\x82ippy");
    |                                       the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
-  --> $DIR/invalid_from_utf8.rs:45:9
+  --> $DIR/invalid_from_utf8.rs:47:9
    |
 LL |         std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^
@@ -53,45 +53,45 @@ LL |         std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy"));
    |                                       the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:62:9
+  --> $DIR/invalid_from_utf8.rs:64:9
    |
 LL |         std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^
-   |                                 |
-   |                                 the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^
+   |                                      |
+   |                                      the literal was valid UTF-8 up to the 2 bytes
    |
 note: the lint level is defined here
-  --> $DIR/invalid_from_utf8.rs:5:9
+  --> $DIR/invalid_from_utf8.rs:7:9
    |
 LL | #![warn(invalid_from_utf8)]
    |         ^^^^^^^^^^^^^^^^^
 
 warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:64:9
+  --> $DIR/invalid_from_utf8.rs:66:9
    |
 LL |         std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^
-   |                                 |
-   |                                 the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                                      |
+   |                                      the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:82:9
+  --> $DIR/invalid_from_utf8.rs:84:9
    |
 LL |         std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]);
-   |         ^^^^^^^^^^^^^^^^^^^^-----------------------------------^
-   |                             |
-   |                             the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^----------------------------------^
+   |                              |
+   |                              the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:84:9
+  --> $DIR/invalid_from_utf8.rs:86:9
    |
 LL |         std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']);
-   |         ^^^^^^^^^^^^^^^^^^^^----------------------------------------------^
-   |                             |
-   |                             the literal was valid UTF-8 up to the 2 bytes
+   |         ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^
+   |                              |
+   |                              the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:86:9
+  --> $DIR/invalid_from_utf8.rs:88:9
    |
 LL |         std::str::from_utf8(b"cl\x82ippy");
    |         ^^^^^^^^^^^^^^^^^^^^-------------^
@@ -99,12 +99,69 @@ LL |         std::str::from_utf8(b"cl\x82ippy");
    |                             the literal was valid UTF-8 up to the 2 bytes
 
 warning: calls to `std::str::from_utf8` with a invalid literal always return an error
-  --> $DIR/invalid_from_utf8.rs:88:9
+  --> $DIR/invalid_from_utf8.rs:90:9
    |
 LL |         std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy"));
    |         ^^^^^^^^^^^^^^^^^^^^---------------------------------^
    |                             |
    |                             the literal was valid UTF-8 up to the 2 bytes
 
-warning: 12 warnings emitted
+warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:97:5
+   |
+LL |     let mut a = [99, 108, 130, 105, 112, 112, 121];
+   |                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+LL |     std::str::from_utf8_mut(&mut a);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:101:5
+   |
+LL |     let mut a = [99, 108, 130, 105, 112, 112, 121];
+   |                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+...
+LL |     std::str::from_utf8_mut(c);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with a invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:104:5
+   |
+LL |     let mut c = &[99, 108, 130, 105, 112, 112, 121];
+   |                  ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+LL |     std::str::from_utf8(c);
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with a invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:107:5
+   |
+LL |     const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
+   |                                ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+LL |     std::str::from_utf8(&INVALID_1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with a invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:110:5
+   |
+LL |     static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121];
+   |                                 ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+LL |     std::str::from_utf8(&INVALID_2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with a invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:113:5
+   |
+LL |     const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121];
+   |                                          ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+LL |     std::str::from_utf8(INVALID_3);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: calls to `std::str::from_utf8` with a invalid literal always return an error
+  --> $DIR/invalid_from_utf8.rs:116:5
+   |
+LL |     const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] };
+   |                                            ---------------------------------- the literal was valid UTF-8 up to the 2 bytes
+LL |     std::str::from_utf8(INVALID_4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 19 warnings emitted
 
diff --git a/tests/ui/async-await/large_moves.rs b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs
index 62b12104694..33113642023 100644
--- a/tests/ui/async-await/large_moves.rs
+++ b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs
@@ -1,10 +1,8 @@
 #![deny(large_assignments)]
 #![feature(large_assignments)]
-#![cfg_attr(attribute, move_size_limit = "1000")]
+#![move_size_limit = "1000"]
 // build-fail
 // only-x86_64
-// revisions: attribute option
-// [option]compile-flags: -Zmove-size-limit=1000
 
 // edition:2018
 // compile-flags: -Zmir-opt-level=0
@@ -12,25 +10,12 @@
 use std::{sync::Arc, rc::Rc};
 
 fn main() {
-    let x = async {
-        let y = [0; 9999];
-        dbg!(y);
-        thing(&y).await;
-        dbg!(y);
-    };
-    let z = (x, 42); //~ ERROR large_assignments
-    let a = z.0; //~ ERROR large_assignments
-    let b = z.1;
     let _ = Arc::new([0; 9999]); // OK!
     let _ = Box::new([0; 9999]); // OK!
     let _ = Rc::new([0; 9999]); // OK!
     let _ = NotBox::new([0; 9999]); //~ ERROR large_assignments
 }
 
-async fn thing(y: &[u8]) {
-    dbg!(y);
-}
-
 struct NotBox {
     data: [u8; 9999],
 }
diff --git a/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr b/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr
new file mode 100644
index 00000000000..b45cbe5da4d
--- /dev/null
+++ b/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr
@@ -0,0 +1,23 @@
+error: moving 9999 bytes
+  --> $DIR/box_rc_arc_allowed.rs:16:13
+   |
+LL |     let _ = NotBox::new([0; 9999]);
+   |             ^^^^^^^^^^^^^^^^^^^^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+note: the lint level is defined here
+  --> $DIR/box_rc_arc_allowed.rs:1:9
+   |
+LL | #![deny(large_assignments)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: moving 9999 bytes
+  --> $DIR/box_rc_arc_allowed.rs:26:13
+   |
+LL |             data,
+   |             ^^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/large_assignments/large_future.attribute.stderr b/tests/ui/lint/large_assignments/large_future.attribute.stderr
new file mode 100644
index 00000000000..734b7ff7ba2
--- /dev/null
+++ b/tests/ui/lint/large_assignments/large_future.attribute.stderr
@@ -0,0 +1,23 @@
+error: moving 10024 bytes
+  --> $DIR/large_future.rs:19:14
+   |
+LL |     let z = (x, 42);
+   |              ^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+note: the lint level is defined here
+  --> $DIR/large_future.rs:1:9
+   |
+LL | #![deny(large_assignments)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: moving 10024 bytes
+  --> $DIR/large_future.rs:20:13
+   |
+LL |     let a = z.0;
+   |             ^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/large_assignments/large_future.option.stderr b/tests/ui/lint/large_assignments/large_future.option.stderr
new file mode 100644
index 00000000000..734b7ff7ba2
--- /dev/null
+++ b/tests/ui/lint/large_assignments/large_future.option.stderr
@@ -0,0 +1,23 @@
+error: moving 10024 bytes
+  --> $DIR/large_future.rs:19:14
+   |
+LL |     let z = (x, 42);
+   |              ^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+note: the lint level is defined here
+  --> $DIR/large_future.rs:1:9
+   |
+LL | #![deny(large_assignments)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: moving 10024 bytes
+  --> $DIR/large_future.rs:20:13
+   |
+LL |     let a = z.0;
+   |             ^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/large_assignments/large_future.rs b/tests/ui/lint/large_assignments/large_future.rs
new file mode 100644
index 00000000000..834746fa97e
--- /dev/null
+++ b/tests/ui/lint/large_assignments/large_future.rs
@@ -0,0 +1,26 @@
+#![deny(large_assignments)]
+#![cfg_attr(attribute, feature(large_assignments))]
+#![cfg_attr(attribute, move_size_limit = "1000")]
+// build-fail
+// only-x86_64
+// revisions: attribute option
+// [option]compile-flags: -Zmove-size-limit=1000
+
+// edition:2018
+// compile-flags: -Zmir-opt-level=0
+
+fn main() {
+    let x = async {
+        let y = [0; 9999];
+        dbg!(y);
+        thing(&y).await;
+        dbg!(y);
+    };
+    let z = (x, 42); //~ ERROR large_assignments
+    let a = z.0; //~ ERROR large_assignments
+    let b = z.1;
+}
+
+async fn thing(y: &[u8]) {
+    dbg!(y);
+}
diff --git a/tests/ui/main-wrong-type.stderr b/tests/ui/main-wrong-type.stderr
index 43efaf884e3..1e5f368758e 100644
--- a/tests/ui/main-wrong-type.stderr
+++ b/tests/ui/main-wrong-type.stderr
@@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type
 LL | fn main(foo: S) {
    | ^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn(S)`
+   = note: expected signature `fn()`
+              found signature `fn(S)`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs
index 775961d3fd7..ae27db7a835 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs
@@ -6,8 +6,5 @@
 use core::panic::PanicInfo;
 
 #[panic_handler]
-fn panic(
-    info: PanicInfo, //~ ERROR argument should be `&PanicInfo`
-) -> () //~ ERROR return type should be `!`
-{
-}
+fn panic(info: PanicInfo) -> () {}
+//~^ `#[panic_handler]` function has wrong type [E0308]
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
index 8b044f7669c..d12bfbf269e 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
@@ -1,14 +1,12 @@
-error: return type should be `!`
-  --> $DIR/panic-handler-bad-signature-1.rs:11:6
+error[E0308]: `#[panic_handler]` function has wrong type
+  --> $DIR/panic-handler-bad-signature-1.rs:9:16
    |
-LL | ) -> ()
-   |      ^^
-
-error: argument should be `&PanicInfo`
-  --> $DIR/panic-handler-bad-signature-1.rs:10:11
+LL | fn panic(info: PanicInfo) -> () {}
+   |                ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>`
    |
-LL |     info: PanicInfo,
-   |           ^^^^^^^^^
+   = note: expected signature `fn(&PanicInfo<'_>) -> !`
+              found signature `fn(PanicInfo<'_>)`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs
index 72793400058..3c3f1513f6f 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs
@@ -6,9 +6,8 @@
 use core::panic::PanicInfo;
 
 #[panic_handler]
-fn panic(
-    info: &'static PanicInfo, //~ ERROR argument should be `&PanicInfo`
-) -> !
+fn panic(info: &'static PanicInfo) -> !
+//~^ #[panic_handler]` function has wrong type [E0308]
 {
     loop {}
 }
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr
index 5ab6934202e..06e32d5fb84 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr
@@ -1,8 +1,12 @@
-error: argument should be `&PanicInfo`
-  --> $DIR/panic-handler-bad-signature-2.rs:10:11
+error[E0308]: `#[panic_handler]` function has wrong type
+  --> $DIR/panic-handler-bad-signature-2.rs:9:1
    |
-LL |     info: &'static PanicInfo,
-   |           ^^^^^^^^^^^^^^^^^^
+LL | fn panic(info: &'static PanicInfo) -> !
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _`
+              found fn pointer `for<'a> fn(&'static PanicInfo<'a>) -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs
index ab9c9d7f417..9e17e32fbb4 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs
@@ -6,6 +6,6 @@
 use core::panic::PanicInfo;
 
 #[panic_handler]
-fn panic() -> ! { //~ ERROR function should have one argument
+fn panic() -> ! { //~ #[panic_handler]` function has wrong type [E0308]
     loop {}
 }
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr
index 0a70181fdac..8365f5769eb 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr
@@ -1,8 +1,12 @@
-error: function should have one argument
+error[E0308]: `#[panic_handler]` function has wrong type
   --> $DIR/panic-handler-bad-signature-3.rs:9:1
    |
 LL | fn panic() -> ! {
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn(&PanicInfo<'_>) -> _`
+              found signature `fn() -> _`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.rs b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs
new file mode 100644
index 00000000000..97307d1b2a4
--- /dev/null
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs
@@ -0,0 +1,13 @@
+// compile-flags:-C panic=abort
+
+#![no_std]
+#![no_main]
+
+use core::panic::PanicInfo;
+
+#[panic_handler]
+fn panic(info: &PanicInfo<'static>) -> !
+//~^ #[panic_handler]` function has wrong type [E0308]
+{
+    loop {}
+}
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr
new file mode 100644
index 00000000000..22b8d5ca811
--- /dev/null
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr
@@ -0,0 +1,12 @@
+error[E0308]: `#[panic_handler]` function has wrong type
+  --> $DIR/panic-handler-bad-signature-5.rs:9:1
+   |
+LL | fn panic(info: &PanicInfo<'static>) -> !
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _`
+              found fn pointer `for<'a> fn(&'a PanicInfo<'static>) -> _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.rs b/tests/ui/panic-handler/panic-handler-with-target-feature.rs
new file mode 100644
index 00000000000..8ea0275d7e9
--- /dev/null
+++ b/tests/ui/panic-handler/panic-handler-with-target-feature.rs
@@ -0,0 +1,15 @@
+// compile-flags:-C panic=abort
+// only-x86_64
+
+#![feature(target_feature_11)]
+#![no_std]
+#![no_main]
+
+use core::panic::PanicInfo;
+
+#[panic_handler]
+#[target_feature(enable = "avx2")]
+//~^ ERROR `panic_impl` language item function is not allowed to have `#[target_feature]`
+fn panic(info: &PanicInfo) -> ! {
+    unimplemented!();
+}
diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr
new file mode 100644
index 00000000000..4210a4200ae
--- /dev/null
+++ b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr
@@ -0,0 +1,11 @@
+error: `panic_impl` language item function is not allowed to have `#[target_feature]`
+  --> $DIR/panic-handler-with-target-feature.rs:11:1
+   |
+LL | #[target_feature(enable = "avx2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | fn panic(info: &PanicInfo) -> ! {
+   | ------------------------------- `panic_impl` language item function is not allowed to have `#[target_feature]`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-1.rs b/tests/ui/parser/issues/issue-98601-delimiter-error-1.rs
new file mode 100644
index 00000000000..cfbbd014d4f
--- /dev/null
+++ b/tests/ui/parser/issues/issue-98601-delimiter-error-1.rs
@@ -0,0 +1,9 @@
+fn foo() {
+    match 0 {
+      _ => {}
+    }
+    if foo
+    }
+} //~ ERROR unexpected closing delimiter: `}`
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-1.stderr b/tests/ui/parser/issues/issue-98601-delimiter-error-1.stderr
new file mode 100644
index 00000000000..d568a4c583a
--- /dev/null
+++ b/tests/ui/parser/issues/issue-98601-delimiter-error-1.stderr
@@ -0,0 +1,16 @@
+error: unexpected closing delimiter: `}`
+  --> $DIR/issue-98601-delimiter-error-1.rs:7:1
+   |
+LL | fn foo() {
+   |          - this delimiter might not be properly closed...
+LL |     match 0 {
+LL |       _ => {}
+   |            -- block is empty, you might have not meant to close it
+...
+LL |     }
+   |     - ...as it matches this but it has different indentation
+LL | }
+   | ^ unexpected closing delimiter
+
+error: aborting due to previous error
+
diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs
new file mode 100644
index 00000000000..254e816cfc9
--- /dev/null
+++ b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs
@@ -0,0 +1,5 @@
+fn main() {
+    todo!();
+}
+
+fn other(_: i32)) {} //~ ERROR unexpected closing delimiter: `)`
diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.stderr b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.stderr
new file mode 100644
index 00000000000..81dd39bb769
--- /dev/null
+++ b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.stderr
@@ -0,0 +1,14 @@
+error: unexpected closing delimiter: `)`
+  --> $DIR/issue-98601-delimiter-error-unexpected-close.rs:5:17
+   |
+LL | fn main() {
+   |           - this opening brace...
+LL |     todo!();
+LL | }
+   | - ...matches this closing brace
+LL |
+LL | fn other(_: i32)) {}
+   |                 ^ unexpected closing delimiter
+
+error: aborting due to previous error
+
diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs
index db455fada3b..a1595685372 100644
--- a/tests/ui/range/issue-54505-no-std.rs
+++ b/tests/ui/range/issue-54505-no-std.rs
@@ -17,9 +17,9 @@ extern "C" fn eh_personality() {}
 static EH_CATCH_TYPEINFO: u8 = 0;
 
 #[panic_handler]
-fn panic_handler() {}
-//~^ ERROR return type should be `!`
-//~| ERROR function should have one argument
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    unimplemented!();
+}
 
 // take a reference to any built-in range
 fn take_range(_r: &impl RangeBounds<i8>) {}
diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr
index 13563d1940c..1694d514f42 100644
--- a/tests/ui/range/issue-54505-no-std.stderr
+++ b/tests/ui/range/issue-54505-no-std.stderr
@@ -1,15 +1,3 @@
-error: return type should be `!`
-  --> $DIR/issue-54505-no-std.rs:20:20
-   |
-LL | fn panic_handler() {}
-   |                    ^
-
-error: function should have one argument
-  --> $DIR/issue-54505-no-std.rs:20:1
-   |
-LL | fn panic_handler() {}
-   | ^^^^^^^^^^^^^^^^^^
-
 error[E0308]: mismatched types
   --> $DIR/issue-54505-no-std.rs:29:16
    |
@@ -130,6 +118,6 @@ help: consider borrowing here
 LL |     take_range(&(..=42));
    |                ++     +
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/resolve/bad-expr-path.stderr b/tests/ui/resolve/bad-expr-path.stderr
index 411130913c8..0392c1fa239 100644
--- a/tests/ui/resolve/bad-expr-path.stderr
+++ b/tests/ui/resolve/bad-expr-path.stderr
@@ -16,8 +16,8 @@ error[E0580]: `main` function has wrong type
 LL | fn main(arguments: Vec<String>) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn(Vec<String>)`
+   = note: expected signature `fn()`
+              found signature `fn(Vec<String>)`
 
 error[E0425]: cannot find function `log` in this scope
   --> $DIR/bad-expr-path.rs:4:5
diff --git a/tests/ui/resolve/bad-expr-path2.stderr b/tests/ui/resolve/bad-expr-path2.stderr
index af3ca99c510..9238b1f7023 100644
--- a/tests/ui/resolve/bad-expr-path2.stderr
+++ b/tests/ui/resolve/bad-expr-path2.stderr
@@ -16,8 +16,8 @@ error[E0580]: `main` function has wrong type
 LL | fn main(arguments: Vec<String>) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
    |
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn(Vec<String>)`
+   = note: expected signature `fn()`
+              found signature `fn(Vec<String>)`
 
 error[E0425]: cannot find function `log` in this scope
   --> $DIR/bad-expr-path2.rs:6:5
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs
index 2c99d8bf1c6..15f062edf0e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 
 #![feature(const_trait_impl, const_closures)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
new file mode 100644
index 00000000000..f25390a9070
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
@@ -0,0 +1,8 @@
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-parse-not-item.rs:7:32
+   |
+LL | const fn test() -> impl ~const Fn() {
+   |                                ^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
index 96ffca6519a..4c45b0e56c6 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
@@ -1,15 +1,8 @@
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closure-trait-method-fail.rs:15:5
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-trait-method-fail.rs:14:39
    |
-LL |     x(())
-   |     ^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const std::ops::FnOnce<((),)>>(x: T) -> i32 {
-   |                                                         ++++++++++++++++++++++++++++++++
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                       ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
index fd0c2911814..a8ef244ea30 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
@@ -1,15 +1,8 @@
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closure-trait-method.rs:15:5
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-trait-method.rs:14:39
    |
-LL |     x(())
-   |     ^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const std::ops::FnOnce<((),)>>(x: T) -> i32 {
-   |                                                         ++++++++++++++++++++++++++++++++
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                       ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
index abf2a2dc511..6d61b23e4b7 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
@@ -1,39 +1,26 @@
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closures.rs:12:5
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:8:19
    |
-LL |     f() * 7
-   |     ^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |         F: ~const FnOnce() -> u8 + ~const std::ops::Fn<()>,
-   |                                  +++++++++++++++++++++++++
+LL |         F: ~const FnOnce() -> u8,
+   |                   ^^^^^^^^^^^^^^
 
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closures.rs:24:5
-   |
-LL |     f() + f()
-   |     ^^^
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:9:19
    |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn answer<F: ~const Fn() -> u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 {
-   |                                      +++++++++++++++++++++++++
+LL |         F: ~const FnMut() -> u8,
+   |                   ^^^^^^^^^^^^^
 
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closures.rs:24:11
-   |
-LL |     f() + f()
-   |           ^^^
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:10:19
    |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
+LL |         F: ~const Fn() -> u8,
+   |                   ^^^^^^^^^^
+
+error: ~const can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:23:27
    |
-LL | const fn answer<F: ~const Fn() -> u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 {
-   |                                      +++++++++++++++++++++++++
+LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
+   |                           ^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs
new file mode 100644
index 00000000000..2f474d978d3
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs
@@ -0,0 +1,11 @@
+// check-pass
+#![feature(const_trait_impl, effects)]
+
+const fn a() {}
+
+fn foo<F: FnOnce()>(a: F) {}
+
+fn main() {
+    let _ = a;
+    foo(a);
+}
diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr
index d723ff538a8..813e65e45a2 100644
--- a/tests/ui/stats/hir-stats.stderr
+++ b/tests/ui/stats/hir-stats.stderr
@@ -146,33 +146,33 @@ hir-stats - Trait                    192 ( 2.1%)             4
 hir-stats WherePredicate           192 ( 2.1%)             3            64
 hir-stats - BoundPredicate           192 ( 2.1%)             3
 hir-stats Block                    288 ( 3.2%)             6            48
-hir-stats Pat                      360 ( 4.0%)             5            72
+hir-stats Pat                      360 ( 3.9%)             5            72
 hir-stats - Wild                      72 ( 0.8%)             1
 hir-stats - Struct                    72 ( 0.8%)             1
 hir-stats - Binding                  216 ( 2.4%)             3
 hir-stats GenericParam             400 ( 4.4%)             5            80
-hir-stats Generics                 560 ( 6.2%)            10            56
-hir-stats Ty                       720 ( 8.0%)            15            48
+hir-stats Generics                 560 ( 6.1%)            10            56
+hir-stats Ty                       720 ( 7.9%)            15            48
 hir-stats - Ptr                       48 ( 0.5%)             1
 hir-stats - Ref                       48 ( 0.5%)             1
-hir-stats - Path                     624 ( 6.9%)            13
-hir-stats Expr                     768 ( 8.5%)            12            64
+hir-stats - Path                     624 ( 6.8%)            13
+hir-stats Expr                     768 ( 8.4%)            12            64
 hir-stats - Path                      64 ( 0.7%)             1
 hir-stats - Struct                    64 ( 0.7%)             1
 hir-stats - Match                     64 ( 0.7%)             1
 hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.4%)             2
 hir-stats - Block                    384 ( 4.2%)             6
-hir-stats Item                     880 ( 9.7%)            11            80
-hir-stats - Trait                     80 ( 0.9%)             1
-hir-stats - Enum                      80 ( 0.9%)             1
-hir-stats - ExternCrate               80 ( 0.9%)             1
-hir-stats - ForeignMod                80 ( 0.9%)             1
-hir-stats - Impl                      80 ( 0.9%)             1
-hir-stats - Fn                       160 ( 1.8%)             2
-hir-stats - Use                      320 ( 3.5%)             4
-hir-stats Path                   1_240 (13.7%)            31            40
-hir-stats PathSegment            1_920 (21.2%)            40            48
+hir-stats Item                     968 (10.6%)            11            88
+hir-stats - Trait                     88 ( 1.0%)             1
+hir-stats - Enum                      88 ( 1.0%)             1
+hir-stats - ExternCrate               88 ( 1.0%)             1
+hir-stats - ForeignMod                88 ( 1.0%)             1
+hir-stats - Impl                      88 ( 1.0%)             1
+hir-stats - Fn                       176 ( 1.9%)             2
+hir-stats - Use                      352 ( 3.9%)             4
+hir-stats Path                   1_240 (13.6%)            31            40
+hir-stats PathSegment            1_920 (21.0%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  9_048
+hir-stats Total                  9_136
 hir-stats
diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs
index f21c9b2c808..c3b201fb1c6 100644
--- a/tests/ui/structs-enums/rec-align-u64.rs
+++ b/tests/ui/structs-enums/rec-align-u64.rs
@@ -37,6 +37,7 @@ struct Outer {
           target_os = "emscripten",
           target_os = "freebsd",
           target_os = "fuchsia",
+          target_os = "hurd",
           target_os = "illumos",
           target_os = "linux",
           target_os = "macos",
diff --git a/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.rs b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.rs
new file mode 100644
index 00000000000..fec0fdc46fb
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.rs
@@ -0,0 +1,9 @@
+#![feature(type_alias_impl_trait)]
+
+pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>;
+//~^ ERROR use of undeclared lifetime name `'db`
+//~| ERROR cannot find type `Key` in this scope
+//~| ERROR unconstrained opaque type
+//~| ERROR unconstrained opaque type
+
+pub fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr
new file mode 100644
index 00000000000..d4aeace4ae7
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr
@@ -0,0 +1,47 @@
+error[E0261]: use of undeclared lifetime name `'db`
+  --> $DIR/nested-impl-trait-in-tait.rs:3:40
+   |
+LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>;
+   |                                        ^^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'db` lifetime
+   |
+LL | pub type Tait = impl for<'db> Iterator<Item = (&'db Key, impl Iterator)>;
+   |                      ++++++++
+help: consider introducing lifetime `'db` here
+   |
+LL | pub type Tait<'db> = impl Iterator<Item = (&'db Key, impl Iterator)>;
+   |              +++++
+
+error[E0412]: cannot find type `Key` in this scope
+  --> $DIR/nested-impl-trait-in-tait.rs:3:44
+   |
+LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>;
+   |                                            ^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL + use std::thread::local_impl::Key;
+   |
+
+error: unconstrained opaque type
+  --> $DIR/nested-impl-trait-in-tait.rs:3:17
+   |
+LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Tait` must be used in combination with a concrete type within the same module
+
+error: unconstrained opaque type
+  --> $DIR/nested-impl-trait-in-tait.rs:3:49
+   |
+LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>;
+   |                                                 ^^^^^^^^^^^^^
+   |
+   = note: `Tait` must be used in combination with a concrete type within the same module
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0261, E0412.
+For more information about an error, try `rustc --explain E0261`.